Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 25, 2019 18:27:52

Room_on
Зарегистрирован: 2019-02-14
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Всем добрый день. Подскажите, пожалуйста, как можно:
1. Создать одну переменную (или массив) и использовать её для чтения в разных процессах? (переменная start_time в коде ниже)
2. Создать одну переменную, которую можно использовать и для чтения и для записи в разных процессах? (переменная counter в коде ниже)

Нужно использование именно multiprocessing, а не multithreading. Читал про Value и Array, но пока не смог понять как их их использовать..

 from multiprocessing import Pool
from datetime import datetime
def main(link):
	global start_time
	global counter
	print(start_time)
	print(link)
	counter += 1
	print(counter)
if __name__ == '__main__':
	global start_time
	global counter
	counter = 0
	start_time = datetime.now()
	links = [1,2,3]
	m = 3
	pool = Pool(m)
	pool.map(main, links)
	pool.close()
	pool.join()

Отредактировано Room_on (Фев. 25, 2019 18:28:18)

Офлайн

#2 Фев. 25, 2019 18:34:27

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Room_on
Принципиальное ограничение процессов - индивидуальное для процесса адресное пространство. (хотя на самом деле можно получить разделяемую память, но не в вашем случае). Межпроцессное взаимодействие осуществляется не так.
https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B5



Офлайн

#3 Фев. 25, 2019 19:22:39

Room_on
Зарегистрирован: 2019-02-14
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

FishHook
Room_onПринципиальное ограничение процессов - индивидуальное для процесса адресное пространство. (хотя на самом деле можно получить разделяемую память, но не в вашем случае)

А почему в моем случае нельзя получить разделяемую память? Мне казалось Value и Array как раз для этого..

Офлайн

#4 Фев. 26, 2019 05:03:28

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Room_on
Мне казалось Value и Array как раз для этого.
Уважаемый друг, Value - это некоторое значение, ценность величина. Array - это массив. Что вы имеете в виду? Вы бы хоть ссылки давали, или примеры кода, или хотя бы намекнули, какую библиотеку смотреть и где конкретные классы Value и Array искать.



Офлайн

#5 Фев. 26, 2019 07:30:09

Room_on
Зарегистрирован: 2019-02-14
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

from multiprocessing import Value, Array
https://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes

Отредактировано Room_on (Фев. 26, 2019 07:30:59)

Офлайн

#6 Фев. 26, 2019 10:53:12

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Room_on
Читал про Value и Array, но пока не смог понять как их их использовать..
ну дык есть же пример, вы сами его приводите
Room_on
https://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes
там вроде адкватный пример жи приведен, все работает, можете скопировать и проверить, что вам конкретно непонятно в использовании Value и Array?
с числами оно работает вообще замечательно, вот с строками там есть нюансы.. поэтому лучше(проще) использовать Manager, там вообще все прозрачно для “погромиста”. Естетсвенно Manager будет помедленее , но зато он способен расшарить общие переменные даже между процессами выполняеммыми на разных машинах в сети.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Фев. 26, 2019 12:04:54)

Офлайн

#7 Фев. 28, 2019 08:51:57

Room_on
Зарегистрирован: 2019-02-14
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

PEHDOM
что вам конкретно непонятно в использовании Value и Array?
Я не понимаю, как использовать их вместе с pool.map
В примере Value и Array передаются в один процесс, а мне нужно передать их в несколько процессов + список, значения из которого будут разбираться процессами и запускать одновременное выполнение функции.
Сможете переделать мой пример с тем, чтобы counter был единый на все процессы?

Отредактировано Room_on (Фев. 28, 2019 08:52:44)

Офлайн

#8 Фев. 28, 2019 12:05:43

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Room_on
В примере Value и Array передаются в один процесс, а мне нужно передать их в несколько процессов + список, значения из которого будут разбираться процессами и запускать одновременное выполнение функции.
тут как раз разницы никакой, вы можете Value и Array передать в два, три… миллион процессов с ровно тем же результатов.
Room_on
Я не понимаю, как использовать их вместе с pool.map
а вот с pool.map там все намного веселее, если вы попытаетесь передать их так же как и “простом примере” то получите исключение типа такого:
RuntimeError: Synchronized objects should only be shared between processes through inheritance
Вобщемто нормального решения этой проблемы пока не существует(ну или я пока не нашел его).
но есть пару -тройку решений. Одно совсем костыльное с использованием globals
 from multiprocessing import Pool, Value
from datetime import datetime
counter = None
start_time = None
def init(cntr, start_t):
    #инициализатор для каждого процесса
    global counter
    global start_time
    counter = cntr
    start_time = start_t
def main(link):
    with counter.get_lock():
        counter.value += 1
    print(counter.value, link, start_time)
if __name__ == '__main__':
    counter = Value('i', 0)
    start_time = datetime.now()
    links = ['a','b','c','d', 'e', 'f']
    m = 3
    with Pool(processes=m, initializer = init, initargs = (counter, start_time)) as pool:
        pool.map(main, links)
        pool.close()
        pool.join()
второй менее костыльный, уже без использования globals, но все равно, ИМХО, немного через #опу.
 from multiprocessing import Pool, Value
from datetime import datetime
def init(func, counter, start_time):
    #инициализатор для каждого процесса
    # передаем счетчик в тупую нашей функции, ведь функция это тоже обьект :)
    func.counter = counter
    func.statr_time = start_time
def main(link):
    counter = main.counter        # вобщем это необязательно, можно просто
    start_time = main.start_time  # писать везде  main.counter или main.start_time
    with counter.get_lock():      # всемсто counter и start_time
        counter.value += 1        #
    print(counter.value, link, start_time)
if __name__ == '__main__':
    counter = Value('i', 0)
    start_time = datetime.now()
    links = ['a','b','c','d', 'e', 'f']
    m = 3
    with Pool(processes=m, initializer = init, initargs = (main, counter, start_time)) as pool:
        pool.map(main, links)
        pool.close()
        pool.join()

Но если использовать Manager() то оно вобщем вполне работает “втупую”, Это ИМХО, вообще некостыльный и самый кошерный метод, единственный минус Manager() таки помедленее будет чем просто Value.
 from multiprocessing import Pool, Manager
from datetime import datetime
from itertools import repeat
def main(link, counter, start_time):
    counter.value += 1
    print(counter.value, link, start_time)
if __name__ == '__main__':
    manager = Manager()
    counter = manager.Value('i', 0)
    start_time = datetime.now()
    links = ['a','b','c','d', 'e', 'f']
    m = 3
    with Pool(processes=m) as pool:
        pool.starmap(main, zip(links, repeat(counter), repeat(start_time)))
        pool.close()
        pool.join()

вывод :
1 a 2019-02-28 12:04:35.360442
2 b 2019-02-28 12:04:35.360442
3 c 2019-02-28 12:04:35.360442
4 d 2019-02-28 12:04:35.360442
5 e 2019-02-28 12:04:35.360442
6 f 2019-02-28 12:04:35.360442



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Фев. 28, 2019 12:27:13)

Офлайн

#9 Март 4, 2019 17:41:25

Room_on
Зарегистрирован: 2019-02-14
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

PEHDOM
Большое спасибо за ответ! Можете подсказать как внутри устроены map и starmap? По моим ощущениям, мне кажется, что они заранее разделяют links (из примера) по процессам, а потом каждый процесс обрабатывает ту часть links, которая ему досталась. Это же справедливо и для потоков. Вывод делаю на основе того, что вначале идет быстрая параллельная обработка, а в конце только один один/процесс поток медленно “доделывает” свою часть. Есть ли возможность сделать так, чтобы они действительно разбирали данные по одному элементу, а не заранее делили их на части? Или они уже так делают и у меня проблема в другом?

Офлайн

#10 Март 4, 2019 21:57:47

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Глобальные переменные и multiprocessing

Room_on
Можете подсказать как внутри устроены map и starmap?
map и starmap работают идентично, разница только в принимаемых аргументах, первый принимает элементы списка и скармливает процессу как есть, а второй распаковывет вложеные списки, и передает уже аргументами.

Room_on
По моим ощущениям, мне кажется, что они заранее разделяют links (из примера) по процессам, а потом каждый процесс обрабатывает ту часть links, которая ему досталась. Это же справедливо и для потоков. Вывод делаю на основе того, что вначале идет быстрая параллельная обработка, а в конце только один один/процесс поток медленно “доделывает” свою часть. Есть ли возможность сделать так, чтобы они действительно разбирали данные по одному элементу, а не заранее делили их на части? Или они уже так делают и у меня проблема в другом?
Они так и делают, это легко проверить простым кодом, пускай линки кратные трем обрабатываються 1 секунду, кратные двум - три, остальне 7:
 from multiprocessing import Pool, Manager
from itertools import repeat
import time
def main(link, counter):
    print(time.strftime('%H:%M:%S', time.localtime()), link, ' - start process' )
    if link%3==0:
        time.sleep(1)
    elif link%2==0:
        time.sleep(3)
    else:
        time.sleep(7)
    counter.value += 1
    print(time.strftime('%H:%M:%S', time.localtime()), link, ' - end process' )
if __name__ == '__main__':
    manager = Manager()
    counter = manager.Value('i', 0)
    links = [1, 2, 3, 4, 5, 6, 7, 8]
    m = 3
    with Pool(processes=m) as pool:
        pool.starmap(main, zip(links, repeat(counter)))
        pool.close()
        pool.join()
>>>
21:48:12 1  - start process
21:48:12 2  - start process
21:48:12 3  - start process
21:48:13 3  - end process
21:48:13 4  - start process
21:48:15 2  - end process
21:48:15 5  - start process
21:48:16 4  - end process
21:48:16 6  - start process
21:48:17 6  - end process
21:48:17 7  - start process
21:48:19 1  - end process
21:48:19 8  - start process
21:48:22 8  - end process
21:48:22 5  - end process
21:48:24 7  - end process
>>>
как видно, пул из 3-х воркеров разбирает задачи по мере завершения, пока обрабатываеться первый линк, третий завершаеться и сразу берется 4-й, завершаеться второй и сразу береться 5-й, … на момент когда первый воркер обработает 1-й линк два остальных воркера разберут 2,3,4,5 и 6. Ну а под конец , таки да приходиться ждать пока последний воркер не завершит свою работу, pool.join() обязывает. Как видно,под конец все остальные воркеры уже закончили работу, и все ждут пока отработает 7-й.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Март 4, 2019 22:01:58)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version