Как использовать многопроцессорную блокировку в экземпляре класса? - PullRequest
0 голосов
/ 01 ноября 2018

Я использую Python 3.7 в Windows.

Что я пытаюсь сделать: - заблокировать метод экземпляра класса, когда другой процесс получил такую ​​же блокировку.

Попытка:

Я уже успешно выполнил this , но я не хочу, чтобы здесь была глобальная переменная для блокировки, а вместо этого одна полностью внутренняя для класса

from multiprocessing import Lock, freeze_support,Pool
from time import sleep

def do_work(name):
    print(name+' waiting for lock to work...',end='')
    sleep(2)
    with lock:
        print('done!')
        print(name+' doing work...',end='')
        sleep(5)
        print('done!')

def init(olock):
    global lock
    lock = olock

if __name__ == '__main__':
    freeze_support()
    args_list = [('a'),('b'),('c')]
    lock=Lock()
    p=Pool(8,initializer=init,initargs=(lock,))
    p.map_async(do_work,args_list)
    p.close()
    p.join()

Когда выполняется этот последний фрагмент кода, из-за блокировки требуется ~ 17,3 секунды . Без блокировки это займет ~ 7 секунд .

Я пытался реализовать это внутри класса, но блокировка ничего не делает, и она всегда выполняется за ~ 7 секунд .

class O():
    def __init__(self):
        self.lock=Lock()
    def __getstate__(self): # used to remove multiprocess object(s) from class, so it can be pickled
        self_dict=self.__dict__.copy()
        del self_dict['lock']
        return self_dict
    def __setstate__(self,state): # used to remove multiprocess object(s) from class, so it can be pickled
        self.__dict__.update(state)
    def _do_work(self,name):
        print(name+' waiting for lock to work...',end='')
        sleep(2)
        with self.lock:
            print('done!')
            print(name+' doing work...',end='')
            sleep(5)
            print('done!')

if __name__ == '__main__':
    freeze_support()
    c = O()
    pool = Pool(8)
    pool.apply_async(c._do_work,('a',))
    pool.apply_async(c._do_work,('b',))
    pool.apply_async(c._do_work,('c',))
    pool.close()
    pool.join()

Вопрос: Итак, что я могу сделать, чтобы заблокировать этот экземпляр класса, когда я вызываю метод, который асинхронно взаимодействует с ресурсом посредством многопроцессорной обработки?

1 Ответ

0 голосов
/ 10 ноября 2018

apply_async выберет объект функции и отправит в рабочий процесс пула по очереди, но, поскольку c._do_work является связанным методом, экземпляр также будет выбран, что приведет к ошибке. Вы могли бы обернуть это в простую функцию:

c = O()
def w(*args):
    return c._do_work(*args)

if __name__ == '__main__':
    pool = Pool(1)
    pool.apply_async(w, ('a',))
    ...

и вы должны удалить __setstate__ / __getstate__.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...