Простой Python. Современный стиль программирования (Любанович) - страница 181

Мы можем воссоздать пример о посуде, основанный на процессах, с помощью потоков:

>import threading, queue

>import time

>def washer(dishes, dish_queue):

>····for dish in dishes:

>····print ("Washing", dish)

>········time.sleep(5)

>········dish_queue.put(dish)

>def dryer(dish_queue):

>····while True:

>········dish = dish_queue.get()

>········print ("Drying", dish)

>········time.sleep(10)

>········dish_queue.task_done()

>dish_queue = queue.Queue()

>for n in range(2):

>····dryer_thread = threading.Thread(target=dryer, args=(dish_queue,))

>········dryer_thread.start()

>dishes = ['salad', 'bread', 'entree', 'desert']

>washer(dishes, dish_queue)

>dish_queue.join()

Различие между модулями multiprocessing и threading заключается в том, что модуль threading не имеет функции terminate(). Не существует простого способа завершить запущенный поток, поскольку это может вызвать разнообразные проблемы в коде и, возможно, даже в пространственно-временном континууме.

Потоки могут быть опасны. Как и управление памятью вручную в языках вроде С и С++, они могут вызвать появление ошибок, которые ужасно трудно найти и исправить. Для того чтобы использовать потоки, весь код программы — и код внешних библиотек, которые он использует, — должен быть потокобезопасным. В предыдущем примере кода потоки не работали с глобальными переменными, поэтому они могли работать независимо, ничего не разрушая.

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

Вы настороженно идете по дому, снимая показатели со своих впечатляющих инструментов. И внезапно замечаете, что подсвечник, мимо которого прошли несколько секунд назад, пропал.

Содержимое дома похоже на переменные программы. Привидения — это потоки процесса (дома). Если бы привидения только просматривали содержимое дома, проблемы бы не было — поток просто считает значение константы или переменной, не пытаясь его изменить.

Однако некая невидимая сущность может схватить ваш фонарик, дунуть холодной струей воздуха на вашу шею, рассыпать шарики на ступеньках или заставить вспыхнуть огонь в камине. Особо утонченные привидения изменили бы что-нибудь в другой комнате, чего вы бы даже не заметили.

Несмотря на ваши шикарные инструменты, вам будет очень трудно разобраться в том, кто, как и когда это сделал.

Если бы вы использовали несколько процессов вместо потоков, это было бы похоже на несколько домов, в которых обитает только одно (живое) существо. Если бы вы поставили бутылку бренди перед камином, она все еще была бы на своем месте час спустя. Возможно, немного жидкости испарилось бы, но сама бутылка осталась бы на том же месте.