Что вам нужно знать

chto vam nuzhno znat?v=1656593771

от Timber.io

HS26etJFGfMC8x2cZbKpLznEx-A790oyvnSs
Фото: Josep Castells на Unsplash

Что такое threading? Почему вы можете этого хотеть?

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

Потоки в Python нельзя использовать для параллельных вычислений ЦБ. Но он идеально подходит для операций ввода-вывода, таких как веб-скрейпинг, поскольку процессор простаивает в ожидании данных.

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

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

Для процессов с интенсивным процессом использование модуля поточной обработки мало пользы.

ovUCmUeZrbYCgom4gc3TcPP9EZtq4INvmwTa

Потоки включены в стандартную библиотеку:

import threading from queueimport Queueimport time

Вы можете использовать target как вызванный объект, args чтобы передать параметры функции, и start чтобы начать нить.

def testThread(num):    print numif __name__ == '__main__':    for i in range(5):        t = threading.Thread(target=testThread, arg=(i,))        t.start()

Если вы никогда не видели if __name__ == '__main__': раньше это в основном способ убедиться, что код, вложенный в него, будет выполняться только если сценарий запускается непосредственно (не импортируется).

Замок

Вы часто хотите, чтобы ваши потоки могли использовать или изменять переменные, общие между потоками. Для этого вам придется использовать что-то известное как a lock.

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

7tzH0eWzoj2WDCWtQ4ofrUxBXhFBjcQ2eZVW

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

Можно заблокировать печать, чтобы гарантировать, что только один поток может печататься одновременно. Это предотвращает смешение текста (и повреждения данных) во время печати.

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

print_lock = threading.Lock()def threadTest():    # when this exits, the print_lock is released    with print_lock:        print(worker)def threader():  while True:    # get the job from the front of the queue    threadTest(q.get())    q.task_done()q = Queue()for x in range(5):    thread = threading.Thread(target = threader)    # this ensures the thread will die when the main thread dies    # can set t.daemon to False if you want it to keep running    t.daemon = True    t.start()for job in range(10):    q.put(job)

Многопоточность не всегда является идеальным решением

Я считаю, что многие руководства, как правило, пропускают негативные стороны использования инструмента, которому они только что пытались вас научить. Важно понимать, что использование всех этих инструментов имеет как плюсы, так и минусы. Например:

  1. Существуют накладные расходы, связанные с управлением потоками, поэтому вы не хотите использовать их для основных задач (например, пример)
  2. Передача потоков увеличивает сложность программы, что может усложнить отладку

Что такое многопроцессорность? Чем он отличается от резьбы?

Без многопроцессорности программы Python имеют проблемы с максимальной эффективностью системы из-за GIL (глобальная блокировка переводчика). Python не был разработан ввиду того, что персональные компьютеры могут иметь более одного ядра (что показывает, насколько старая речь).

GIL необходим, поскольку Python не является потокобезопасным, а при доступе к объекту Python существует глобальная принудительная блокировка. Хотя это не идеальный механизм, он достаточно эффективный механизм управления памятью. Что мы можем сделать?

Многопроцессорность позволяет создавать программы, которые могут выполняться одновременно (в обход GIL) и использовать все ядро ​​вашего ЦП. Хотя она принципиально отличается от библиотеки потоков, синтаксис очень похож. Многопроцессорная библиотека дает каждому процессу собственный интерпретатор Python, и каждому свой собственный GIL.

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

Давайте начнем

import multiprocessingdef spawn():  print('test!')if __name__ == '__main__':  for i in range(5):    p = multiprocessing.Process(target=spawn)    p.start()

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

for i in range(5):  p = multiprocessing.Process(target=spawn)  p.start()  p.join() # this line allows you to wait for processes

Если вы хотите передать аргументы своему процессу, вы можете сделать это с помощью args:

import multiprocessingdef spawn(num):  print(num)if __name__ == '__main__':  for i in range(25):    ## right here    p = multiprocessing.Process(target=spawn, args=(i,))    p.start()

Вот отличный пример, потому что числа не в том порядке, который вы ожидали (без p.join()).

Недостатки

Как и в случае с потоками, у многопроцессорной обработки все еще есть недостатки… вам нужно выбрать свой яд:

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

Вывод

Когда следует использовать многопоточность или многопроцессорность?

  • Если в вашем коде много ввода-вывода или использования сети, многопоточность является лучшим выбором из-за низких затрат.
  • Если у вас есть графический интерфейс, используйте многопоточность, чтобы поток пользовательского интерфейса не блокировался.
  • Если ваш код привязан к ЦБ, вам следует использовать многопроцессорную обработку (если ваша машина имеет несколько ядер)

Просто оговорка: мы лесозаготовительная компания @ Timber. Нам было бы очень приятно, если бы вы попробовали наш продукт (это действительно здорово!), но это все, что мы собираемся его рекламировать.

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

TfypoIZnTArPPIDyCyeOzyDi8ybZKDcqnaq6

Первоначально опубликовано на timber.io.

Добавить комментарий

Ваш адрес email не будет опубликован.