English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Недавно изучал параллелизм в Python, поэтому сделал краткое резюме о многопоточности, многопроцессности, асинхронности и корутинах.
1. Многопоточность
Многопоточность позволяет существовать нескольким контроллерам в одном процессе, чтобы несколько функций могли быть активны одновременно, что позволяет выполнять операции нескольких функций одновременно. Даже на компьютере с одним процессором можно создать эффект многопоточности, постоянно переключаясь между инструкциями различных потоков.
Многопоточность эквивалентна параллельной системе. Параллельные системы обычно выполняют несколько задач одновременно. Если несколько задач могут делиться ресурсами, особенно когда они одновременно пишут в переменную, необходимо решить проблему синхронизации, например, в системе продажи билетов на поезда с многопоточностью: одна команда проверяет, проданы ли все билеты, а другая команда продает билеты через несколько окон, что может привести к продаже несуществующих билетов.
В условиях параллелизма порядок выполнения инструкций определяется ядром. Внутри одного потока инструкции выполняются в порядке их следования, но трудно сказать, какая инструкция из других потоков будет выполнена первой. Поэтому нужно учитывать проблемы синхронизации многопоточности. Синхронизация (synchronization) означает, что в определенный момент времени только один поток может обращаться к определенным ресурсам.
1. Модуль thread
2. Модуль threading
threading.Thread создает поток.
Чтобы проверить наличие оставшихся билетов и продать их, добавьте mutex lock, чтобы не произошло так, что один поток только что определил, что нет оставшихся билетов, а другой поток выполняет операцию продажи билетов.
#! /usr/bin/python #-* coding: utf-8 -* # __author__ ="tyomcat" import threading import time import os def booth(tid): global i global lock while True: lock.acquire() if i!=0: i=i-1 print "Окно:", tid,", оставшиеся билеты:", i time.sleep(1) else: print "Thread_id", tid, "No more tickets" os._exit(0) lock.release() time.sleep(1) i = 100 lock=threading.Lock() for k in range(10): new_thread = threading.Thread(target=booth, args=(k,)) new_thread.start()
2. Корoutines (также известные как microthreads, fibers)
Корoutines, в отличие от抢占ного调度 потоков, это кооперативный调度. Корoutines также являются монопоточными, но они позволяют писать код, который в противном случае пришлось бы использовать асинхронный + способ回调, как будто он синхронный.
1. В python корoutines могут быть реализованы генераторами (generator).
Сначала нужно иметь扎实 понимание генераторов и yield.
Вызов обычной функции python, как правило, начинается с первого строки кода и заканчивается инструкцией return, исключительной ситуацией или выполнением функции (можно также считать, что выполняется неявный return None).
Если функция возвращает управление вызывателю, это означает, что все закончилось. Иногда можно создать функцию, которая может производить последовательность, чтобы «сохранить свою работу», это и есть генератор (функция, использующая ключевое слово yield).
Можем «продолжить последовательность» потому что функция не возвращает, как это обычно понимается. Слова «return» подразумевают, что функция возвращает управление в место вызова функции. А слово «yield» означает, что передача управления временная и добровольная, и функция впоследствии又能 вернуть управление.
Посмотрите на пример производителя/потребителя:
#! /usr/bin/python #-* coding: utf-8 -* # __author__ ="tyomcat" import time import sys # Producer def produce(l): i=0 while 1: if i < 10: l.append(i) yield i i=i+1 time.sleep(1) else: return # Конsumer def consume(l): p = produce(l) while 1: try: p.next() while len(l) > 0: print l.pop() except StopIteration: sys.exit(0) if __name__ == "__main__": l = [] consume(l)
Когда программа выполняется до produce yield i, возвращается генератор и выполнение приостанавливается. Когда мы вызываем p.next() в custom, программа возвращается к produce yield i и продолжает выполнять, и снова элемент добавляется в l, затем мы выполняем print l.pop(), до тех пор, пока p.next() не вызовет исключение StopIteration.
2、Stackless Python
3、Модуль greenlet
Реализация на основе greenlet имеет производительность,仅次于 Stackless Python,大约 в два раза медленнее, чем Stackless Python, и почти в один уровень быстрее, чем другие решения. Фактически, greenlet не является真正的 механизмом параллелизации, а представляет собой切换 между различными кодовыми блоками выполнения различных функций в одной и той же строке, реализуя принцип «ты работай немного, я работай немного», и при переключении необходимо указать, когда切换 и на что切换.
4、Модуль eventlet
3、Множественные процессы
1、Подпроцесс (subprocess пакет)
В Python через пакет subprocess можно fork-овать подпроцесс и запустить внешнюю программу.
Когда вызывается команда системы, первым делом стоит подумать о модуле os. Операции проводят с помощью os.system() и os.popen(). Однако эти команды слишком просты и не могут выполнить некоторые сложные операции, такие как предоставление ввода для выполняемой команды или чтение вывода команды, определение состояния выполнения команды, управление параллельным выполнением множества команд и т.д. В этом случае команда Popen из модуля subprocess может эффективно выполнить необходимые нам операции
>>> import subprocess >>> command_line = raw_input() ping -c 10 www.baidu.com >>> args = shlex.split(command_line) >>> p = subprocess.Popen(args)
Используя subprocess.PIPE, можно соединить вход и выход нескольких подпроцессов, образуя канал (pipe):
import subprocess child1 = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE) child2 = subprocess.Popen(["wc"], stdin=child1.stdout, stdout=subprocess.PIPE) out = child2.communicate() print(out)
метод communicate() читает данные из stdout и stderr и вводит их в stdin.
2)、многопоточность (библиотека multiprocessing)
1)、библиотека multiprocessing — это пакет управления многопоточностью в Python. Как и threading.Thread, она может использовать объект multiprocessing.Process для создания процесса.
Пул процессов (Process Pool) может создавать несколько процессов.
apply_async(func,args) извлекает процесс из пулла для выполнения func, args — это параметры func. Он вернёт объект AsyncResult, на который можно вызвать метод get() для получения результата.
close() пул процессов больше не будет создавать новых процессов
join() ждёт завершение всех процессов в пуле. Перед использованием join() необходимо вызвать метод close() для Pool.
!/usr/bin/env python # -*- coding:utf-8 -*- # __author__ == "tyomcat" # "У моего компьютера 4 cpu" from multiprocessing import Pool import os, time def long_time_task(name): print 'Запуск задачи %s (%s)...' % (name, os.getpid()) start = time.time() time.sleep(3) end = time.time() print 'Task %s runs %0.2f seconds.' % (name, (end - start)) if __name__ == 'main__': print 'Parent process %s.' % os.getpid() p = Pool() for i in range(4): p.apply_async(long_time_task, args=(i,)) print 'Waiting for all subprocesses done...' p.close() p.join() print 'All subprocesses done.'
(2) Общий доступ к ресурсам многопоточности
Через.shared_memory и объект Manager: один процесс работает как сервер, а Manager используется для хранения ресурсов.
Другие процессы могут получить доступ к Manager через параметры или адреса, установив соединение, они могут работать с ресурсами на сервере.
!/usr/bin/env python # -*- coding:utf-8 -*- # __author__ == "tyomcat" from multiprocessing import Queue, Pool import multiprocessing, time, random def write(q): for value in ['A', 'B', 'C', 'D']: print "Put %s to Queue!" % value q.put(value) time.sleep(random.random()) def read(q, lock): while True: lock.acquire() if not q.empty(): value = q.get(True) print "Get %s from Queue" % value time.sleep(random.random()) else: break lock.release() if __name__ == "__main__": manager = multiprocessing.Manager() q = manager.Queue() p=Pool() lock=manager.Lock() pw=p.apply_async(write,args=(q,)) pr=p.apply_async(read,args=(q,lock)) p.close() p.join() print print "Все данные записаны и прочитаны"
Четвертый раздел: асинхронный
Будь то поток или процесс, они используют синхронный порядок, при блокировке производительность значительно снижается, не充分利用 потенциал CPU,浪费硬件 инвестиции, и更重要的是, это приводит к железобетонной структуре модулей программного обеспечения, плотной взаимосвязи, которые невозможно разделить,不利于 будущей расширяемости и изменений.
Будь то процесс или поток, каждый блок и переход требуют вызова системного вызова (system call), сначала позволяя CPU запускать планировщик операционной системы, а затем планировщик определяет,哪一个 процесс (поток) будет запускаться.
В настоящее время популярные асинхронные серверы основаны на модели событийного驱жения (например, nginx).
В асинхронной модели событийного驱жения операции, вызывающие блокировку, преобразуются в асинхронные операции, а主线负责发起这个 асинхронную операцию и обрабатывать результаты этой операции. Поскольку все блокирующие операции преобразуются в асинхронные операции, теоретически большая часть времени主线 занимаема реальными вычислительными задачами, уменьшая время调度 многопоточности, поэтому производительность этой модели обычно лучше.
Это все содержимое статьи, надеюсь, это поможет вам в изучении, и希望大家多多支持呐喊教程。
Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему владельцу. Контент предоставлен пользователями Интернета, загружен пользователями самостоятельно, сайт не обладает правами собственности, не был обработан вручную, и не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите спорное содержимое о нарушении авторских прав, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @) для жалоб,并提供相关证据. Если обнаружено, сайт немедленно удаляет спорное содержимое.