Отправка многопроцессорных заданий Python на основе совокупных критериев для всех запущенных заданий - PullRequest
0 голосов
/ 12 июня 2018

Критерии агрегирования на основе многопроцессорной обработки заданий Python для всех запущенных заданий

У меня есть задание, которое должно выполнить некоторую работу с базой данных Teradata и в качестве аргумента принимает количество сеансов БД.В базе данных установлен максимальный предел 60 сессий на количество дБ.Могу ли я использовать многопроцессорную обработку для условной обработки заданий, чтобы сумма (num_db_sessions) во всех активных дочерних процессах <= max_num_db_sessions? </p>

Я просто вставляю некоторый псевдокод ниже:

import multiprocessing as mp
import time

def dbworker(db_object, num_db_sessions):
    # do work on db_object #####
    # The sum(num_db_sessions) <= max_num_db_sessions 
    print (db_object, num_db_sessions)
    # The db_objs with larger num_db_sessions take longer to finish
    time.sleep(num_db_sessions)
    return

if __name__ == "__main__":
    max_num_db_sessions = 60
    # JobsList (db_object,num_db_sessions)
    jobs_list = [('A', 15), ('B', 15), ('C', 15), ('D', 15)
                , ('E', 1), ('F', 1), ('G', 1), ('H', 1)
                , ('I', 1), ('J', 1), ('K', 1), ('L', 1)
                , ('M', 2), ('N', 1), ('O', 1), ('P', 1)
                , ('Q', 2), ('R', 2), ('S', 2), ('T', 2)
                , ('U', 2), ('V', 2), ('W', 2), ('X', 2)
                , ('Y', 2), ('Z', 2)]
    ## Submit jobs_list to mutltiprocessing ####
    for db_object,num_db_sessions in jobs_list:
        dbworker(db_object,num_db_sessions) ## -->>> sum(num_db_sessions) <=  max_num_db_sessions
    ## Is this possible ??

1 Ответ

0 голосов
/ 13 июня 2018

Я понял это.Код ниже делает это.Ключевые элементы:

1) Запустить отдельный процесс демона, чтобы поместить задачи в очередь.Целевая функция для этого выполняет оркестровку

2) Реализует счетчик как multiprocessing.value, который отслеживает текущее количество запущенных сеансов.Реализация счетчика была взята из https://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing

3) Реализовать multiprocessing.manager (). List () для отслеживания неподтвержденных заданий.

4) Использование ядовитых таблетокчтобы прервать рабочий процесс, отправив None * number_of_child_processes, как это реализовано в подходе отравленной таблетки.Это было взято из https://pymotw.com/3/multiprocessing/communication.html

Рабочая функция использует time.sleep (num_db_sessions) в качестве способа имитации рабочей нагрузки (большее время обработки)

Вот код.

import multiprocessing
import time
class Counter(object):
    def __init__(self, initval=0):
        self.val = multiprocessing.Value('i', initval)
        self.lock = multiprocessing.Lock()

    def increment(self,val):
        with self.lock:
            self.val.value += val

    def value(self):
        with self.lock:
            return self.val.value

def queue_manager(tasks,results,jobs_list,counter,max_num_db_sessions,num_consumers):
    proc_name = multiprocessing.current_process().name
    while len(jobs_list) > 0:
        current_counter = counter.value()
        available_sessions = max_num_db_sessions - current_counter
        if available_sessions > 0:
            prop_list = [(p,s) for p,s in jobs_list if s <= available_sessions]
            if (len(prop_list)) > 0:
                with multiprocessing.Lock():
                    print(prop_list[0])
                    tasks.put(prop_list[0][0])
                    jobs_list.remove(prop_list[0])

                counter.increment(prop_list[0][1])
                print("Process: {} -- submitted:{} Counter is:{} Sessions:{}".format(proc_name
                                                                          , prop_list[0][0]
                                                                          , current_counter
                                                                          , available_sessions)
                      )
        else:
            print("Process: {} -- Sleeping:{} Counter is:{} Sessions:{}".format(proc_name
                                                                                 , str(5)
                                                                                 , current_counter
                                                                                 , available_sessions)
            )
            time.sleep(5)
    else:
        for i in range(num_consumers):
            tasks.put(None)

def worker(tasks,counter,proc_list):
    proc_name = multiprocessing.current_process().name
    while True:
        obj = tasks.get()
        if obj is None:
            break
        name,age = [(name,sess) for name,sess in proc_list if name == obj][0]
        print("Process: {} -- Processing:{} Sleeping for:{} Counter is:{}".format(proc_name
                                                                              ,name
                                                                              ,age
                                                                              ,counter.value())
              )
        time.sleep(age)
        counter.increment(-age)
        print("Process: {} -- Exiting:{} Sleeping for:{} Counter is:{}".format(proc_name
                                                                              ,name
                                                                              ,age
                                                                              ,counter.value())
              )

if __name__ == '__main__':
    max_num_db_sessions = 60
    tasks = multiprocessing.JoinableQueue()
    results = multiprocessing.Queue() # This will be unused now. But will use it.
    mpmanager = multiprocessing.Manager()
    proc_list = [('A', 15), ('B', 15), ('C', 15), ('D', 15)
                , ('E', 1), ('F', 1), ('G', 1), ('H', 1)
                , ('I', 1), ('J', 1), ('K', 1), ('L', 1)
                , ('M', 2), ('N', 1), ('O', 1), ('P', 1)
                , ('Q', 2), ('R', 2), ('S', 2), ('T', 2)
                , ('U', 2), ('V', 2), ('W', 2), ('X', 2)
                , ('Y', 2), ('Z', 2)]
    jobs_list = mpmanager.list(proc_list)
    counter = Counter(0)
    num_cpu = 3
    d = multiprocessing.Process(name='Queue_manager_proc'
                                ,target=queue_manager
                                ,args=(tasks, results, jobs_list, counter
                                       , max_num_db_sessions, num_cpu)
                                )
    d.daemon = True
    d.start()
    jobs = []
    for i in range(num_cpu):
        p = multiprocessing.Process(name="Worker_proc_{}".format(str(i+1))
                                    ,target=worker
                                    ,args=(tasks,counter,proc_list)
                                    )
        jobs.append(p)
        p.start()

    for job in jobs:
        job.join()

    d.join()
...