Документация Python неофициальный перевод

multiprocessing.md

2445 строк · 204.0 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.11/library/multiprocessing.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) – параллелизм на основе процессов89**Исходный код:** [Lib/multiprocessing/](https://python-all.ru/src/3.11/Lib/multiprocessing)1011---1213[Доступность](https://python-all.ru/3.11/library/intro.html#availability): not Emscripten, not WASI.1415Этот модуль не работает или недоступен на платформах WebAssembly `wasm32-emscripten` и `wasm32-wasi`. См. [платформы WebAssembly](https://python-all.ru/3.11/library/intro.html#wasm-availability) для получения дополнительной информации.1617## Введение1819[`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) – это пакет, который поддерживает порождение процессов с помощью API, похожего на модуль [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading). Пакет [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) предоставляет как локальную, так и удалённую конкурентность, обходя [глобальную блокировку интерпретатора](https://python-all.ru/3.11/glossary.html#term-global-interpreter-lock) за счёт использования подпроцессов вместо потоков. Благодаря этому модуль [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) позволяет программисту полностью задействовать несколько процессоров на данной машине. Он работает как в Unix, так и в Windows.2021Модуль [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) также предоставляет API, у которых нет аналогов в модуле [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading). Яркий пример – объект [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), который предоставляет удобный способ распараллеливания выполнения функции для нескольких входных значений, распределяя входные данные между процессами (параллелизм данных). Следующий пример демонстрирует обычную практику определения таких функций в модуле, чтобы дочерние процессы могли успешно импортировать этот модуль. Этот базовый пример параллелизма данных с использованием [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool),2223```python24from multiprocessing import Pool2526def f(x):27    return x*x2829if __name__ == '__main__':30    with Pool(5) as p:31        print(p.map(f, [1, 2, 3]))32```3334будет выводить на стандартный вывод3536```python37[1, 4, 9]38```3940> **См. также**41>42> [`concurrent.futures.ProcessPoolExecutor`](https://python-all.ru/3.11/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) предлагает интерфейс более высокого уровня для отправки задач фоновому процессу без блокировки выполнения вызывающего процесса. По сравнению с прямым использованием интерфейса [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), API [`concurrent.futures`](https://python-all.ru/3.11/library/concurrent.futures.html#module-concurrent.futures) позволяет легче разделить отправку работы в пул процессов и ожидание результатов.4344### Класс [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process)4546В [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) процессы порождаются созданием объекта [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) и последующим вызовом его метода [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start). [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) следует API [`threading.Thread`](https://python-all.ru/3.11/library/threading.html#threading.Thread). Простой пример многопроцессной программы:4748```python49from multiprocessing import Process5051def f(name):52    print('hello', name)5354if __name__ == '__main__':55    p = Process(target=f, args=('bob',))56    p.start()57    p.join()58```5960Чтобы показать идентификаторы задействованных процессов, вот расширенный пример:6162```python63from multiprocessing import Process64import os6566def info(title):67    print(title)68    print('module name:', __name__)69    print('parent process:', os.getppid())70    print('process id:', os.getpid())7172def f(name):73    info('function f')74    print('hello', name)7576if __name__ == '__main__':77    info('main line')78    p = Process(target=f, args=('bob',))79    p.start()80    p.join()81```8283Объяснение того, зачем нужна часть `if __name__ == '__main__'`, см. в [руководстве по программированию](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-programming).8485### Контексты и методы запуска8687В зависимости от платформы [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) поддерживает три способа запуска процесса. Эти *методы запуска*:8889> ***spawn***90>91> Родительский процесс запускает новый процесс интерпретатора Python. Дочерний процесс унаследует только те ресурсы, которые необходимы для выполнения метода [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run) объекта процесса. В частности, ненужные файловые дескрипторы и дескрипторы из родительского процесса не наследуются. Запуск процесса с помощью этого метода довольно медленный по сравнению с использованием *fork* или *forkserver*.92>93> Доступно на Unix и Windows. По умолчанию используется на Windows и macOS.94>95> ***fork***96>97> Родительский процесс использует [`os.fork()`](https://python-all.ru/3.11/library/os.html#os.fork) для форка интерпретатора Python. Дочерний процесс в начале своего выполнения фактически идентичен родительскому процессу. Все ресурсы родительского процесса наследуются дочерним процессом. Обратите внимание, что безопасный форк многопоточного процесса проблематичен.98>99> Доступно только на Unix. По умолчанию используется на Unix.100>101> ***forkserver***102>103> Когда программа запускается и выбирает метод запуска *forkserver*, запускается серверный процесс. После этого каждый раз, когда требуется новый процесс, родительский процесс подключается к серверу и запрашивает создание (fork) нового процесса. Серверный процесс (fork server) является однопоточным, поэтому ему безопасно использовать [`os.fork()`](https://python-all.ru/3.11/library/os.html#os.fork). Ненужные ресурсы не наследуются.104>105> Доступно на платформах Unix, которые поддерживают передачу файловых дескрипторов через каналы Unix.106107Изменено в версии 3.4: метод запуска *spawn* добавлен на всех платформах Unix, а *forkserver* добавлен для некоторых платформ Unix. Дочерние процессы больше не наследуют все наследуемые дескрипторы родительского процесса в Windows.108109Изменено в версии 3.8: На macOS метод запуска *spawn* теперь используется по умолчанию. Метод запуска *fork* следует считать небезопасным, так как он может приводить к сбоям подпроцесса, поскольку системные библиотеки macOS могут запускать потоки. См. [bpo-33725](https://python-all.ru/3.11/library/multiprocessing.html).110111На POSIX использование методов запуска *spawn* или *forkserver* также запускает процесс *resource tracker* (отслеживатель ресурсов), который отслеживает удалённые именованные системные ресурсы (такие как именованные семафоры или объекты [`SharedMemory`](https://python-all.ru/3.11/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory)), созданные процессами программы. Когда все процессы завершатся, отслеживатель ресурсов удаляет все оставшиеся отслеживаемые объекты. Обычно их не должно быть, но если процесс был убит сигналом, могут остаться некоторые «утекшие» ресурсы. (Ни утекшие семафоры, ни разделяемые сегменты памяти не будут автоматически удалены до следующей перезагрузки. Это проблематично для обоих типов объектов, так как система допускает лишь ограниченное количество именованных семафоров, а разделяемые сегменты памяти занимают некоторое место в основной памяти.)112113Для выбора метода запуска используется [`set_start_method()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.set_start_method) в блоке `if __name__ == '__main__'` главного модуля. Например:114115```python116import multiprocessing as mp117118def foo(q):119    q.put('hello')120121if __name__ == '__main__':122    mp.set_start_method('spawn')123    q = mp.Queue()124    p = mp.Process(target=foo, args=(q,))125    p.start()126    print(q.get())127    p.join()128```129130[`set_start_method()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.set_start_method) не должен использоваться более одного раза в программе.131132В качестве альтернативы можно использовать [`get_context()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.get_context) для получения объекта контекста. Объекты контекста имеют тот же API, что и модуль multiprocessing, и позволяют использовать несколько методов запуска в одной программе.133134```python135import multiprocessing as mp136137def foo(q):138    q.put('hello')139140if __name__ == '__main__':141    ctx = mp.get_context('spawn')142    q = ctx.Queue()143    p = ctx.Process(target=foo, args=(q,))144    p.start()145    print(q.get())146    p.join()147```148149Обратите внимание: объекты, связанные с одним контекстом, могут быть несовместимы с процессами другого контекста. В частности, блокировки, созданные с помощью контекста *fork*, нельзя передавать процессам, запущенным с помощью методов запуска *spawn* или *forkserver*.150151Библиотека, которая хочет использовать определённый метод запуска, вероятно, должна использовать [`get_context()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.get_context), чтобы не мешать выбору пользователя библиотеки.152153> **Предупреждение**154>155> Методы запуска `'spawn'` и `'forkserver'` в настоящее время не могут использоваться с «замороженными» исполняемыми файлами (т.е. бинарными файлами, созданными такими пакетами, как **PyInstaller** и **cx\_Freeze**) на Unix. Метод запуска `'fork'` работает.156157### Обмен объектами между процессами158159[`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) поддерживает два типа каналов связи между процессами:160161**Очереди**162163> Класс [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue) является почти точной копией [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue). Например:164>165> ```python166> from multiprocessing import Process, Queue167>168> def f(q):169>     q.put([42, None, 'hello'])170>171> if __name__ == '__main__':172>     q = Queue()173>     p = Process(target=f, args=(q,))174>     p.start()175>     print(q.get())    # печатает "[42, None, 'hello']"176>     p.join()177> ```178>179> Очереди потокобезопасны и безопасны для процессов.180181**Каналы**182183> Функция [`Pipe()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe) возвращает пару объектов соединения, связанных каналом, который по умолчанию является дуплексным (двунаправленным). Например:184>185> ```python186> from multiprocessing import Process, Pipe187>188> def f(conn):189>     conn.send([42, None, 'hello'])190>     conn.close()191>192> if __name__ == '__main__':193>     parent_conn, child_conn = Pipe()194>     p = Process(target=f, args=(child_conn,))195>     p.start()196>     print(parent_conn.recv())   # печатает "[42, None, 'hello']"197>     p.join()198> ```199>200> Два объекта соединения, возвращаемые [`Pipe()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe), представляют два конца канала. Каждый объект соединения имеет методы `send()` и `recv()` (среди прочих). Обратите внимание: данные в канале могут быть повреждены, если два процесса (или потока) попытаются одновременно читать или писать в *один и тот же* конец канала. Разумеется, нет риска повреждения, если процессы одновременно используют разные концы канала.201202### Синхронизация между процессами203204[`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) содержит эквиваленты всех примитивов синхронизации из [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading). Например, можно использовать блокировку, чтобы гарантировать, что только один процесс одновременно выводит на стандартный вывод:205206```python207from multiprocessing import Process, Lock208209def f(l, i):210    l.acquire()211    try:212        print('hello world', i)213    finally:214        l.release()215216if __name__ == '__main__':217    lock = Lock()218219    for num in range(10):220        Process(target=f, args=(lock, num)).start()221```222223Без использования блокировки вывод от разных процессов может полностью перепутаться.224225### Совместное использование состояния между процессами226227Как уже упоминалось, при параллельном программировании обычно лучше избегать использования общего состояния, насколько это возможно. Это особенно верно при использовании нескольких процессов.228229Однако если действительно необходимо использовать некоторые общие данные, то [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) предоставляет несколько способов сделать это.230231**Разделяемая память**232233> Данные могут храниться в отображении разделяемой памяти с помощью [`Value`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Value) или [`Array`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Array). Например, следующий код234>235> ```python236> from multiprocessing import Process, Value, Array237>238> def f(n, a):239>     n.value = 3.1415927240>     for i in range(len(a)):241>         a[i] = -a[i]242>243> if __name__ == '__main__':244>     num = Value('d', 0.0)245>     arr = Array('i', range(10))246>247>     p = Process(target=f, args=(num, arr))248>     p.start()249>     p.join()250>251>     print(num.value)252>     print(arr[:])253> ```254>255> выведет256>257> ```python258> 3.1415927259> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]260> ```261>262> Аргументы `'d'` и `'i'`, используемые при создании `num` и `arr`, – это коды типов, аналогичные используемым модулем [`array`](https://python-all.ru/3.11/library/array.html#module-array): `'d'` означает число с плавающей запятой двойной точности, а `'i'` – целое число со знаком. Эти разделяемые объекты будут безопасными для процессов и потоков.263>264> Для большей гибкости при работе с разделяемой памятью можно использовать модуль [`multiprocessing.sharedctypes`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.sharedctypes), который поддерживает создание произвольных объектов ctypes, выделенных из разделяемой памяти.265266**Серверный процесс**267268> Объект-менеджер, возвращаемый [`Manager()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Manager), управляет серверным процессом, который содержит объекты Python и позволяет другим процессам манипулировать ими с помощью прокси.269>270> Менеджер, возвращаемый [`Manager()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Manager), поддерживает типы [`list`](https://python-all.ru/3.11/library/stdtypes.html#list), [`dict`](https://python-all.ru/3.11/library/stdtypes.html#dict), [`Namespace`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.Namespace), [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock), [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock), [`Semaphore`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Semaphore), [`BoundedSemaphore`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.BoundedSemaphore), [`Condition`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Condition), [`Event`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Event), [`Barrier`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Barrier), [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue), [`Value`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Value) и [`Array`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Array). Например,271>272> ```python273> from multiprocessing import Process, Manager274>275> def f(d, l):276>     d[1] = '1'277>     d['2'] = 2278>     d[0.25] = None279>     l.reverse()280>281> if __name__ == '__main__':282>     with Manager() as manager:283>         d = manager.dict()284>         l = manager.list(range(10))285>286>         p = Process(target=f, args=(d, l))287>         p.start()288>         p.join()289>290>         print(d)291>         print(l)292> ```293>294> выведет295>296> ```python297> {0.25: None, 1: '1', '2': 2}298> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]299> ```300>301> Серверные менеджеры процессов более гибкие, чем использование объектов разделяемой памяти, потому что их можно настроить на поддержку произвольных типов объектов. Кроме того, один менеджер может быть разделён между процессами на разных компьютерах через сеть. Однако они медленнее, чем использование разделяемой памяти.302303### Использование пула рабочих процессов304305Класс [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool) представляет пул рабочих процессов. Он имеет методы, которые позволяют передавать задачи рабочим процессам несколькими различными способами.306307Например:308309```python310from multiprocessing import Pool, TimeoutError311import time312import os313314def f(x):315    return x*x316317if __name__ == '__main__':318    # запустить 4 рабочих процесса319    with Pool(processes=4) as pool:320321        # печатает "[0, 1, 4,..., 81]"322        print(pool.map(f, range(10)))323324        # печатает те же числа в произвольном порядке325        for i in pool.imap_unordered(f, range(10)):326            print(i)327328        # вычисляет "f(20)" асинхронно329        res = pool.apply_async(f, (20,))      # выполняется *только* в одном процессе330        print(res.get(timeout=1))             # печатает "400"331332        # вычисляет "os.getpid()" асинхронно333        res = pool.apply_async(os.getpid, ()) # выполняется *только* в одном процессе334        print(res.get(timeout=1))             # печатает PID этого процесса335336        # запуск нескольких асинхронных вычислений *может* задействовать больше процессов337        multiple_results = [pool.apply_async(os.getpid, ()) for i in range(4)]338        print([res.get(timeout=1) for res in multiple_results])339340        # усыпить один рабочий процесс на 10 секунд341        res = pool.apply_async(time.sleep, (10,))342        try:343            print(res.get(timeout=1))344        except TimeoutError:345            print("We lacked patience and got a multiprocessing.TimeoutError")346347        print("For the moment, the pool remains available for more work")348349    # выход из блока 'with' остановил пул350    print("Now the pool is closed and no longer available")351```352353Обратите внимание: методы пула должны использоваться только тем процессом, который его создал.354355> **Примечание**356>357> Для функциональности этого пакета требуется, чтобы модуль `__main__` был импортируемым дочерними процессами. Это описано в [Рекомендациях по программированию](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-programming), но стоит упомянуть об этом и здесь. Это означает, что некоторые примеры, такие как примеры [`multiprocessing.pool.Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), не будут работать в интерактивном интерпретаторе. Например:358>359> ```python360> >>> from multiprocessing import Pool361> >>> p = Pool(5)362> >>> def f(x):363> ...     return x*x364> ...365> >>> with p:366> ...     p.map(f, [1,2,3])367> Process PoolWorker-1:368> Process PoolWorker-2:369> Process PoolWorker-3:370> Traceback (most recent call last):371> Traceback (most recent call last):372> Traceback (most recent call last):373> AttributeError: Can't get attribute 'f' on <module '__main__' (built-in)>374> AttributeError: Can't get attribute 'f' on <module '__main__' (built-in)>375> AttributeError: Can't get attribute 'f' on <module '__main__' (built-in)>376> ```377>378> (Если попробовать это сделать, на самом деле будет выведено три полных трассировки стека, перемешанных в полу-случайном порядке, и, возможно, придётся как-то остановить родительский процесс.)379380## Ссылка381382Пакет [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) в основном повторяет API модуля [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading).383384### [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) и исключения385386#### `class multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)`387388Объекты Process представляют активность, выполняемую в отдельном процессе. Класс [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) имеет эквиваленты всех методов [`threading.Thread`](https://python-all.ru/3.11/library/threading.html#threading.Thread).389390Конструктор всегда следует вызывать с именованными аргументами. *group* всегда должен быть `None`; он существует только для совместимости с [`threading.Thread`](https://python-all.ru/3.11/library/threading.html#threading.Thread). *target* – это вызываемый объект, который будет вызван методом [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run). По умолчанию `None`, то есть ничего не вызывается. *name* – это имя процесса (см. [`name`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.name) для подробностей). *args* – кортеж аргументов для вызова целевой функции. *kwargs* – это словарь именованных аргументов для вызова целевой функции. Если указан, аргумент только по ключевому слову *daemon* устанавливает флаг процесса [`daemon`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.daemon) в `True` или `False`. Если `None` (по умолчанию), этот флаг будет унаследован от создающего процесса.391392По умолчанию в *target* не передаётся никаких аргументов. Аргумент *args*, по умолчанию равный `()`, можно использовать для указания списка или кортежа аргументов, передаваемых в *target*.393394Если подкласс переопределяет конструктор, он должен вызывать конструктор базового класса (`Process.__init__()`) перед любыми другими действиями над процессом.395396Изменено в версии 3.3: Добавлен параметр *daemon*.397398#### `run()`399400Метод, представляющий активность процесса.401402Этот метод можно переопределить в подклассе. Стандартный метод [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run) вызывает вызываемый объект, переданный конструктору объекта в качестве аргумента target, если он есть, с позиционными и именованными аргументами, взятыми из аргументов *args* и *kwargs* соответственно.403404Использование списка или кортежа в качестве аргумента *args*, переданного в [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), даёт тот же эффект.405406Пример:407408```python409>>> from multiprocessing import Process410>>> p = Process(target=print, args=[1])411>>> p.run()4121413>>> p = Process(target=print, args=(1,))414>>> p.run()4151416```417418#### `start()`419420Запускает активность процесса.421422Этот метод должен быть вызван не более одного раза для каждого объекта процесса. Он обеспечивает вызов метода [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run) объекта в отдельном процессе.423424#### `join([timeout])`425426Если необязательный аргумент *timeout* равен `None` (по умолчанию), метод блокируется до завершения процесса, у которого вызывается метод [`join()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.join). Если *timeout* – положительное число, блокировка длится не более *timeout* секунд. Обратите внимание: метод возвращает `None`, если процесс завершился или истекло время ожидания. Проверьте [`exitcode`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.exitcode) процесса, чтобы определить, завершился ли он.427428Процесс может быть присоединён много раз.429430Процесс не может присоединить сам себя, так как это приведёт к взаимоблокировке. Попытка вызвать join для процесса до его запуска является ошибкой.431432#### `name`433434Имя процесса. Имя – это строка, используемая только для идентификации. Оно не имеет семантического значения. Несколько процессов могут иметь одно и то же имя.435436Начальное имя устанавливается конструктором. Если явное имя не передано конструктору, создаётся имя вида ‘Process-N1:N2:…:Nk’, где каждая Nk – это N-й дочерний процесс своего родителя.437438#### `is_alive()`439440Возвращает, жив ли процесс.441442Грубо говоря, объект процесса живёт с момента возврата метода [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start) до завершения дочернего процесса.443444#### `daemon`445446Флаг демона процесса (логическое значение). Должен быть установлен до вызова [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start).447448Начальное значение наследуется от создающего процесса.449450Когда процесс завершается, он пытается завершить все свои дочерние процессы-демоны.451452Обратите внимание, что процессу-демону не разрешается создавать дочерние процессы. Иначе процесс-демон оставил бы своих потомков осиротевшими, если бы он был завершён при выходе своего родительского процесса. Кроме того, это **не** демоны или службы Unix, а обычные процессы, которые будут завершены (и не присоединены), если не-демонические процессы завершились.453454В дополнение к API [`threading.Thread`](https://python-all.ru/3.11/library/threading.html#threading.Thread) объекты [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) также поддерживают следующие атрибуты и методы:455456#### `pid`457458Возвращает идентификатор процесса. До запуска процесса это будет `None`.459460#### `exitcode`461462Код выхода дочернего процесса. Будет равно `None`, если процесс ещё не завершён.463464Если метод [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run) дочернего процесса завершился нормально, код выхода будет 0. Если он был завершён через [`sys.exit()`](https://python-all.ru/3.11/library/sys.html#sys.exit) с целочисленным аргументом *N*, код выхода будет *N*.465466Если дочерний процесс завершился из-за необработанного исключения внутри [`run()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.run), код выхода будет 1. Если он был завершён сигналом *N*, код выхода будет отрицательным значением *-N*.467468#### `authkey`469470Ключ аутентификации процесса (байтовая строка).471472При инициализации [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) главному процессу назначается случайная строка с помощью [`os.urandom()`](https://python-all.ru/3.11/library/os.html#os.urandom).473474При создании объекта [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) он наследует ключ аутентификации своего родительского процесса, хотя его можно изменить, установив [`authkey`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.authkey) в другую байтовую строку.475476См. [Ключи аутентификации](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-auth-keys).477478#### `sentinel`479480Числовой дескриптор системного объекта, который становится «готов» по завершении процесса.481482Это значение можно использовать для ожидания нескольких событий одновременно с помощью [`multiprocessing.connection.wait()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.wait). В противном случае вызов [`join()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.join) проще.483484В Windows это дескриптор ОС, который можно использовать с семейством `WaitForSingleObject` и `WaitForMultipleObjects` вызовов API. В Unix это файловый дескриптор, который можно использовать с примитивами из модуля [`select`](https://python-all.ru/3.11/library/select.html#module-select).485486Новое в версии 3.3.487488#### `terminate()`489490Завершает процесс. В POSIX это делается с помощью сигнала [`SIGTERM`](https://python-all.ru/3.11/library/signal.html#signal.SIGTERM); в Windows используется `TerminateProcess()`. Обратите внимание, что обработчики выхода и блоки finally и т.п. не будут выполнены.491492Обратите внимание, что процессы-потомки *не* будут завершены – они просто станут осиротевшими.493494> **Предупреждение**495>496> Если этот метод используется, когда связанный процесс использует канал или очередь, то канал или очередь могут быть повреждены и стать непригодными для использования другими процессами. Аналогично, если процесс захватил блокировку или семафор и т.п., то его завершение может привести к взаимной блокировке других процессов.497498#### `kill()`499500То же, что и [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.terminate), но с использованием сигнала `SIGKILL` в Unix.501502Добавлено в версии 3.7.503504#### `close()`505506Закрывает объект [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), освобождая все связанные с ним ресурсы. Если соответствующий процесс ещё выполняется, возбуждается [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError). После успешного возврата из [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.close) большинство других методов и атрибутов объекта [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process) будут возбуждать [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError).507508Добавлено в версии 3.7.509510Обратите внимание: методы [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start), [`join()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.join), [`is_alive()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.is_alive), [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.terminate) и [`exitcode`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.exitcode) должны вызываться только тем процессом, который создал объект процесса.511512Пример использования некоторых методов [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process):513514```pycon515>>> import multiprocessing, time, signal516>>> p = multiprocessing.Process(target=time.sleep, args=(1000,))517>>> print(p, p.is_alive())518<Process ... initial> False519>>> p.start()520>>> print(p, p.is_alive())521<Process ... started> True522>>> p.terminate()523>>> time.sleep(0.1)524>>> print(p, p.is_alive())525<Process ... stopped exitcode=-SIGTERM> False526>>> p.exitcode == -signal.SIGTERM527True528```529530#### `exception multiprocessing.ProcessError`531532Базовый класс всех исключений [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing).533534#### `exception multiprocessing.BufferTooShort`535536Исключение, возбуждаемое `Connection.recv_bytes_into()`, когда предоставленный буфер слишком мал для чтения сообщения.537538Если `e` является экземпляром [`BufferTooShort`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.BufferTooShort), то `e.args[0]` вернёт сообщение в виде байтовой строки.539540#### `exception multiprocessing.AuthenticationError`541542Возбуждается при ошибке аутентификации.543544#### `exception multiprocessing.TimeoutError`545546Возбуждается методами с тайм-аутом по истечении тайм-аута.547548### Каналы и очереди549550При использовании нескольких процессов обычно применяется передача сообщений для взаимодействия между процессами, что позволяет избежать использования примитивов синхронизации, таких как блокировки.551552Для передачи сообщений можно использовать [`Pipe()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe) (для соединения между двумя процессами) или очередь (которая допускает несколько производителей и потребителей).553554Типы [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue), [`SimpleQueue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.SimpleQueue) и [`JoinableQueue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue) – это очереди с несколькими производителями и потребителями, работающие по принципу FIFO и созданные по образцу класса [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue) из стандартной библиотеки. Они отличаются тем, что в [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue) отсутствуют методы [`task_done()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.task_done) и [`join()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.join), введённые в класс [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue) в Python 2.5.555556Если используется [`JoinableQueue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue), то **обязательно** вызывайте [`JoinableQueue.task_done()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.task_done) для каждой задачи, извлечённой из очереди; в противном случае семафор, используемый для подсчёта незавершённых задач, может переполниться, что приведёт к возбуждению исключения.557558Обратите внимание, что общую очередь также можно создать с помощью объекта-менеджера – см. [Менеджеры](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-managers).559560> **Примечание**561>562> [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) использует обычные исключения [`queue.Empty`](https://python-all.ru/3.11/library/queue.html#queue.Empty) и [`queue.Full`](https://python-all.ru/3.11/library/queue.html#queue.Full) для сигнализации тайм-аута. Они недоступны в пространстве имён [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing), поэтому их необходимо импортировать из [`queue`](https://python-all.ru/3.11/library/queue.html#module-queue).563564> **Примечание**565>566> Когда объект помещается в очередь, он сериализуется с помощью модуля pickle, и фоновый поток позднее сбрасывает сериализованные данные в нижележащий канал. Это имеет некоторые неожиданные последствия, но обычно не вызывает практических трудностей – если это действительно беспокоит, можно вместо этого использовать очередь, созданную с помощью [менеджера](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-managers).567>568> 1. После помещения объекта в пустую очередь может пройти бесконечно малая задержка, прежде чем метод [`empty()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.empty) очереди вернёт [`False`](https://python-all.ru/3.11/library/constants.html#False) и [`get_nowait()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.get_nowait) сможет вернуться без возбуждения [`queue.Empty`](https://python-all.ru/3.11/library/queue.html#queue.Empty).569> 2. Если несколько процессов помещают объекты в очередь, возможно получение объектов на другом конце не по порядку. Однако объекты, помещённые в очередь одним и тем же процессом, всегда будут идти друг за другом в ожидаемом порядке.570571> **Предупреждение**572>573> Если процесс завершается принудительно с помощью [`Process.terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.terminate) или [`os.kill()`](https://python-all.ru/3.11/library/os.html#os.kill) в то время, как он пытается использовать [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue), данные в очереди могут быть повреждены. Это может привести к тому, что любой другой процесс при попытке использовать очередь получит исключение.574575> **Предупреждение**576>577> Как упоминалось выше, если дочерний процесс поместил элементы в очередь (и не использовал [`JoinableQueue.cancel_join_thread`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.cancel_join_thread)), он не завершится, пока все буферизованные элементы не будут сброшены в канал.578>579> Это означает, что при попытке присоединиться к этому процессу может возникнуть взаимоблокировка, если не быть уверенным, что все помещённые в очередь элементы были потреблены. Аналогично, если дочерний процесс не является демоническим, родительский процесс может зависнуть при завершении, когда попытается присоединиться ко всем своим недемоническим потомкам.580>581> Обратите внимание, что очередь, созданная с помощью менеджера, не имеет этой проблемы. См. [Рекомендации по программированию](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-programming).582583Пример использования очередей для межпроцессного взаимодействия см. в разделе [Примеры](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-examples).584585#### `multiprocessing.Pipe([duplex])`586587Возвращает пару `(conn1, conn2)` объектов [`Connection`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection), представляющих концы канала.588589Если *duplex* равно `True` (по умолчанию), то канал двунаправленный. Если *duplex* равно `False`, то канал однонаправленный: `conn1` можно использовать только для получения сообщений, а `conn2` – только для отправки.590591#### `class multiprocessing.Queue([maxsize])`592593Возвращает общедоступную очередь для процессов, реализованную с помощью канала и нескольких блокировок/семафоров. Когда процесс впервые помещает элемент в очередь, запускается поток-загрузчик, который передаёт объекты из буфера в канал.594595Обычные исключения [`queue.Empty`](https://python-all.ru/3.11/library/queue.html#queue.Empty) и [`queue.Full`](https://python-all.ru/3.11/library/queue.html#queue.Full) из модуля [`queue`](https://python-all.ru/3.11/library/queue.html#module-queue) стандартной библиотеки возбуждаются для сигнализации тайм-аутов.596597[`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue) реализует все методы [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue), за исключением [`task_done()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.task_done) и [`join()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.join).598599#### `qsize()`600601Возвращает приблизительный размер очереди. Из-за семантики многопоточности/многопроцессности это число не является надёжным.602603Обратите внимание, что это может вызывать [`NotImplementedError`](https://python-all.ru/3.11/library/exceptions.html#NotImplementedError) на платформах Unix, таких как macOS, где `sem_getvalue()` не реализован.604605#### `empty()`606607Возвращает `True`, если очередь пуста, иначе `False`. Из-за семантики многопоточности/многопроцессности это ненадёжно.608609#### `full()`610611Возвращает `True`, если очередь заполнена, иначе `False`. Из-за семантики многопоточности/многопроцессности это ненадёжно.612613#### `put(obj[, block[, timeout]])`614615Помещает obj в очередь. Если необязательный аргумент *block* равен `True` (по умолчанию) и *timeout* равен `None` (по умолчанию), при необходимости блокируется до появления свободного места. Если *timeout* положительное число, блокируется не более чем на *timeout* секунд и возбуждает исключение [`queue.Full`](https://python-all.ru/3.11/library/queue.html#queue.Full), если за это время свободное место не появилось. В противном случае (*block* равен `False`) помещает элемент в очередь, если свободное место доступно немедленно, иначе возбуждает исключение [`queue.Full`](https://python-all.ru/3.11/library/queue.html#queue.Full) (*timeout* в этом случае игнорируется).616617Изменено в версии 3.8: Если очередь закрыта, возбуждается [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError) вместо [`AssertionError`](https://python-all.ru/3.11/library/exceptions.html#AssertionError).618619#### `put_nowait(obj)`620621Эквивалентно `put(obj, False)`.622623#### `get([block[, timeout]])`624625Удаляет и возвращает элемент из очереди. Если необязательный аргумент *block* равен `True` (по умолчанию) и *timeout* равен `None` (по умолчанию), при необходимости блокируется до появления элемента. Если *timeout* положительное число, блокируется не более чем на *timeout* секунд и возбуждает исключение [`queue.Empty`](https://python-all.ru/3.11/library/queue.html#queue.Empty), если за это время элемент не появился. В противном случае (block равен `False`) возвращает элемент, если он доступен немедленно, иначе возбуждает исключение [`queue.Empty`](https://python-all.ru/3.11/library/queue.html#queue.Empty) (*timeout* в этом случае игнорируется).626627Изменено в версии 3.8: Если очередь закрыта, возбуждается [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError) вместо [`OSError`](https://python-all.ru/3.11/library/exceptions.html#OSError).628629#### `get_nowait()`630631Эквивалентно `get(False)`.632633[`multiprocessing.Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue) имеет несколько дополнительных методов, отсутствующих в [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue). Обычно эти методы не нужны в большинстве кода:634635#### `close()`636637Указывает, что текущий процесс больше не будет помещать данные в эту очередь. Фоновый поток завершится после того, как сбросит все буферизованные данные в канал. Этот метод вызывается автоматически при сборке мусора очереди.638639#### `join_thread()`640641Присоединяет фоновый поток. Этот метод можно использовать только после вызова [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.close). Он блокируется до завершения фонового потока, гарантируя, что все данные из буфера сброшены в канал.642643По умолчанию, если процесс не является создателем очереди, при завершении он попытается присоединить фоновый поток очереди. Процесс может вызвать [`cancel_join_thread()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.cancel_join_thread), чтобы сделать [`join_thread()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.join_thread) бездействующим.644645#### `cancel_join_thread()`646647Предотвращает блокировку [`join_thread()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.join_thread). В частности, это предотвращает автоматическое присоединение фонового потока при завершении процесса – см. [`join_thread()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.join_thread).648649Более удачным названием для этого метода могло бы быть `allow_exit_without_flush()`. Он, скорее всего, приведёт к потере поставленных в очередь данных, и вам почти наверняка не понадобится его использовать. Он существует только на случай, если нужно немедленно завершить текущий процесс, не дожидаясь сброса данных из очереди в нижележащий канал, и потеря данных не имеет значения.650651> **Примечание**652>653> Функциональность этого класса требует работающей реализации общего семафора в хост-операционной системе. Без неё функциональность класса будет отключена, а попытки создать экземпляр [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue) приведут к [`ImportError`](https://python-all.ru/3.11/library/exceptions.html#ImportError). См. [bpo-3770](https://python-all.ru/3.11/library/multiprocessing.html) для дополнительной информации. То же самое относится и ко всем специализированным типам очередей, перечисленным ниже.654655#### `class multiprocessing.SimpleQueue`656657Это упрощённый тип [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue), очень похожий на [`Pipe`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe) с блокировкой.658659#### `close()`660661Закрыть очередь: освободить внутренние ресурсы.662663После закрытия очередь нельзя использовать. Например, методы [`get()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.SimpleQueue.get), [`put()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.SimpleQueue.put) и [`empty()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.SimpleQueue.empty) больше нельзя вызывать.664665Новое в версии 3.9.666667#### `empty()`668669Возвращает `True`, если очередь пуста, иначе `False`.670671#### `get()`672673Извлекает и возвращает элемент из очереди.674675#### `put(item)`676677Помещает *item* в очередь.678679#### `class multiprocessing.JoinableQueue([maxsize])`680681[`JoinableQueue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue), подкласс [`Queue`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue), – это очередь, которая дополнительно имеет методы [`task_done()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.task_done) и [`join()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.join).682683#### `task_done()`684685Указывает, что ранее поставленная в очередь задача завершена. Используется потребителями очереди. Для каждого [`get()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.get), используемого для получения задачи, последующий вызов [`task_done()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.task_done) сообщает очереди, что обработка задачи завершена.686687Если [`join()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.join) в данный момент заблокирован, он возобновится, когда все элементы будут обработаны (то есть для каждого элемента, который был [`put()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.put) в очередь, был получен вызов [`task_done()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.task_done)).688689Вызывает [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError), если вызывается больше раз, чем было помещено элементов в очередь.690691#### `join()`692693Блокируется до тех пор, пока все элементы в очереди не будут извлечены и обработаны.694695Счётчик незавершённых задач увеличивается каждый раз, когда элемент добавляется в очередь. Счётчик уменьшается, когда потребитель вызывает [`task_done()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.JoinableQueue.task_done), чтобы указать, что элемент извлечён и вся работа над ним завершена. Когда счётчик незавершённых задач падает до нуля, [`join()`](https://python-all.ru/3.11/library/queue.html#queue.Queue.join) разблокируется.696697### Разное698699#### `multiprocessing.active_children()`700701Возвращает список всех активных дочерних процессов текущего процесса.702703Вызов этой функции имеет побочный эффект – «присоединение» всех уже завершённых процессов.704705#### `multiprocessing.cpu_count()`706707Возвращает количество процессоров в системе.708709Это число не равно количеству процессоров, которые текущий процесс может использовать. Количество доступных процессоров можно получить с помощью `len(os.sched_getaffinity(0))`710711Если количество процессоров не удаётся определить, вызывается [`NotImplementedError`](https://python-all.ru/3.11/library/exceptions.html#NotImplementedError).712713> **См. также**714>715> [`os.cpu_count()`](https://python-all.ru/3.11/library/os.html#os.cpu_count)716717#### `multiprocessing.current_process()`718719Возвращает объект [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), соответствующий текущему процессу.720721Аналог [`threading.current_thread()`](https://python-all.ru/3.11/library/threading.html#threading.current_thread).722723#### `multiprocessing.parent_process()`724725Возвращает объект [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), соответствующий родительскому процессу [`current_process()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.current_process). Для главного процесса `parent_process` будет `None`.726727Новое в версии 3.8.728729#### `multiprocessing.freeze_support()`730731Добавляет поддержку для случая, когда программа, использующая [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing), была заморожена для создания исполняемого файла Windows. (Протестировано с **py2exe**, **PyInstaller** и **cx\_Freeze**.)732733Эту функцию необходимо вызвать сразу после строки `if __name__ == '__main__'` в главном модуле. Например:734735```python736from multiprocessing import Process, freeze_support737738def f():739    print('hello world!')740741if __name__ == '__main__':742    freeze_support()743    Process(target=f).start()744```745746Если строка `freeze_support()` опущена, то попытка запустить замороженный исполняемый файл вызовет [`RuntimeError`](https://python-all.ru/3.11/library/exceptions.html#RuntimeError).747748Вызов `freeze_support()` не имеет эффекта при запуске на любой операционной системе, кроме Windows. Кроме того, если модуль запускается обычным образом интерпретатором Python в Windows (программа не была заморожена), то `freeze_support()` также не имеет эффекта.749750#### `multiprocessing.get_all_start_methods()`751752Возвращает список поддерживаемых методов запуска, первый из которых является методом по умолчанию. Возможными методами запуска являются `'fork'`, `'spawn'` и `'forkserver'`. В Windows доступен только `'spawn'`. В Unix `'fork'` и `'spawn'` всегда поддерживаются, причём `'fork'` используется по умолчанию.753754Новое в версии 3.4.755756#### `multiprocessing.get_context(method=None)`757758Возвращает объект контекста, который имеет те же атрибуты, что и модуль [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing).759760Если *method* равен `None`, то возвращается контекст по умолчанию. В противном случае *method* должен быть `'fork'`, `'spawn'`, `'forkserver'`. [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError) вызывается, если указанный метод запуска недоступен.761762Новое в версии 3.4.763764#### `multiprocessing.get_start_method(allow_none=False)`765766Возвращает имя метода запуска, используемого для запуска процессов.767768Если метод запуска не был задан и *allow\_none* равен false, то метод запуска фиксируется как используемый по умолчанию, и возвращается его название. Если метод запуска не был задан и *allow\_none* равен true, то возвращается `None`.769770Возвращаемое значение может быть `'fork'`, `'spawn'`, `'forkserver'` или `None`. `'fork'` является значением по умолчанию в Unix, тогда как `'spawn'` – по умолчанию в Windows и macOS.771772Новое в версии 3.4.773774Изменено в версии 3.8: В macOS метод запуска *spawn* теперь используется по умолчанию. Метод запуска *fork* следует считать небезопасным, так как он может привести к краху подпроцесса. См. [bpo-33725](https://python-all.ru/3.11/library/multiprocessing.html).775776#### `multiprocessing.set_executable(executable)`777778Устанавливает путь к интерпретатору Python, используемому при запуске дочернего процесса. (По умолчанию используется [`sys.executable`](https://python-all.ru/3.11/library/sys.html#sys.executable)). Тем, кто встраивает Python, вероятно, потребуется сделать нечто вроде779780```python781set_executable(os.path.join(sys.exec_prefix, 'pythonw.exe'))782```783784прежде чем они смогут создавать дочерние процессы.785786Изменено в версии 3.4: Теперь поддерживается в Unix при использовании метода запуска `'spawn'`.787788Изменено в версии 3.11: Принимает [path-like object](https://python-all.ru/3.11/glossary.html#term-path-like-object).789790#### `multiprocessing.set_start_method(method, force=False)`791792Устанавливает метод, который должен использоваться для запуска дочерних процессов. Аргумент *method* может быть `'fork'`, `'spawn'` или `'forkserver'`. Вызывает [`RuntimeError`](https://python-all.ru/3.11/library/exceptions.html#RuntimeError), если метод запуска уже был установлен и *force* не равно `True`. Если *method* равно `None` и *force* равно `True`, то метод запуска устанавливается в `None`. Если *method* равно `None` и *force* равно `False`, то контекст устанавливается в контекст по умолчанию.793794Обратите внимание, что эта функция должна вызываться не более одного раза, и она должна быть защищена внутри блока `if __name__ == '__main__'` главного модуля.795796Новое в версии 3.4.797798> **Примечание**799>800> [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) не содержит аналогов [`threading.active_count()`](https://python-all.ru/3.11/library/threading.html#threading.active_count), [`threading.enumerate()`](https://python-all.ru/3.11/library/threading.html#threading.enumerate), [`threading.settrace()`](https://python-all.ru/3.11/library/threading.html#threading.settrace), [`threading.setprofile()`](https://python-all.ru/3.11/library/threading.html#threading.setprofile), [`threading.Timer`](https://python-all.ru/3.11/library/threading.html#threading.Timer) или [`threading.local`](https://python-all.ru/3.11/library/threading.html#threading.local).801802### Объекты подключения803804Объекты подключения позволяют отправлять и получать сериализуемые (picklable) объекты или строки. Их можно рассматривать как ориентированные на сообщения соединённые сокеты.805806Объекты подключения обычно создаются с помощью [`Pipe`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe) – см. также [Слушатели и клиенты](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-listeners-clients).807808#### `class multiprocessing.connection.Connection`809810#### `send(obj)`811812Отправляет объект на другой конец подключения; его следует читать с помощью [`recv()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.recv).813814Объект должен быть сериализуемым. Очень большие сериализованные объекты (примерно от 32 МиБ, хотя зависит от ОС) могут вызвать исключение [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError).815816#### `recv()`817818Возвращает объект, отправленный с другого конца подключения с помощью [`send()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.send). Блокируется, пока не появятся данные для получения. Вызывает [`EOFError`](https://python-all.ru/3.11/library/exceptions.html#EOFError), если больше нечего получать и другой конец был закрыт.819820#### `fileno()`821822Возвращает файловый дескриптор или дескриптор (handle), используемый подключением.823824#### `close()`825826Закрывает подключение.827828Вызывается автоматически при сборке мусора для подключения.829830#### `poll([timeout])`831832Возвращает, есть ли данные для чтения.833834Если *timeout* не указан, то метод возвращается немедленно. Если *timeout* – число, то оно задаёт максимальное время блокировки в секундах. Если *timeout* равно `None`, то используется бесконечное ожидание.835836Обратите внимание: с помощью [`multiprocessing.connection.wait()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.wait) можно одновременно опрашивать несколько объектов подключения.837838#### `send_bytes(buffer[, offset[, size]])`839840Отправляет байтовые данные из [байтоподобного объекта](https://python-all.ru/3.11/glossary.html#term-bytes-like-object) как полное сообщение.841842Если задан *offset*, то данные читаются с этой позиции в *buffer*. Если задан *size*, то из буфера будет прочитано соответствующее количество байт. Очень большие буферы (примерно от 32 МиБ, хотя это зависит от ОС) могут возбудить исключение [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError)843844#### `recv_bytes([maxlength])`845846Возвращает полное сообщение из байтовых данных, отправленное с другого конца подключения, в виде строки. Блокируется, пока не появятся данные для получения. Вызывает [`EOFError`](https://python-all.ru/3.11/library/exceptions.html#EOFError), если больше нечего получать и другой конец закрыт.847848Если указан *maxlength* и сообщение длиннее *maxlength*, то вызывается [`OSError`](https://python-all.ru/3.11/library/exceptions.html#OSError), и подключение больше не будет доступно для чтения.849850Изменено в версии 3.3: Ранее эта функция вызывала [`IOError`](https://python-all.ru/3.11/library/exceptions.html#IOError), которая теперь является псевдонимом [`OSError`](https://python-all.ru/3.11/library/exceptions.html#OSError).851852#### `recv_bytes_into(buffer[, offset])`853854Читает в *buffer* полное сообщение с байтовыми данными, отправленное с другого конца соединения, и возвращает количество байтов в сообщении. Блокирует выполнение, пока не появится что-то для приёма. Возбуждает [`EOFError`](https://python-all.ru/3.11/library/exceptions.html#EOFError), если больше нечего принимать и другой конец был закрыт.855856*buffer* должен быть доступным для записи [байтоподобным объектом](https://python-all.ru/3.11/glossary.html#term-bytes-like-object). Если задан *offset*, то сообщение будет записано в буфер, начиная с этой позиции. Offset должен быть неотрицательным целым числом, меньшим длины *buffer* (в байтах).857858Если буфер слишком мал, то вызывается исключение `BufferTooShort` и полное сообщение доступно как `e.args[0]`, где `e` экземпляр исключения.859860Изменено в версии 3.3: Теперь объекты подключения могут передаваться между процессами с помощью [`Connection.send()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.send) и [`Connection.recv()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.recv).861862Объекты подключения также теперь поддерживают протокол менеджера контекста – см. [Типы менеджеров контекста](https://python-all.ru/3.11/library/stdtypes.html#typecontextmanager). [`__enter__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__enter__) возвращает объект подключения, а [`__exit__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__exit__) вызывает [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.close).863864Например:865866```pycon867>>> from multiprocessing import Pipe868>>> a, b = Pipe()869>>> a.send([1, 'hello', None])870>>> b.recv()871[1, 'hello', None]872>>> b.send_bytes(b'thank you')873>>> a.recv_bytes()874b'thank you'875>>> import array876>>> arr1 = array.array('i', range(5))877>>> arr2 = array.array('i', [0] * 10)878>>> a.send_bytes(arr1)879>>> count = b.recv_bytes_into(arr2)880>>> assert count == len(arr1) * arr1.itemsize881>>> arr2882array('i', [0, 1, 2, 3, 4, 0, 0, 0, 0, 0])883```884885> **Предупреждение**886>887> Метод [`Connection.recv()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.recv) автоматически десериализует полученные данные, что может быть угрозой безопасности, если нельзя доверять процессу, отправившему сообщение.888>889> Поэтому, если объект подключения не был создан с помощью `Pipe()` следует использовать методы [`recv()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.recv) и [`send()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.send) только после выполнения некоторой аутентификации. См. [Ключи аутентификации](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-auth-keys).890891> **Предупреждение**892>893> Если процесс завершается принудительно во время чтения или записи в канал, данные в канале, скорее всего, повредятся, так как может стать невозможно определить границы сообщений.894895### Примитивы синхронизации896897В целом, в многопроцессных программах примитивы синхронизации требуются не так часто, как в многопоточных. См. документацию модуля [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading).898899Обратите внимание, что примитивы синхронизации можно также создавать с помощью объекта менеджера – см. [Менеджеры](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-managers).900901#### `class multiprocessing.Barrier(parties[, action[, timeout]])`902903Объект барьера: клон [`threading.Barrier`](https://python-all.ru/3.11/library/threading.html#threading.Barrier).904905Новое в версии 3.3.906907#### `class multiprocessing.BoundedSemaphore([value])`908909Объект ограниченного семафора: близкий аналог [`threading.BoundedSemaphore`](https://python-all.ru/3.11/library/threading.html#threading.BoundedSemaphore).910911Имеется единственное отличие от его близкого аналога: первый аргумент метода `acquire` называется *block*, что согласуется с [`Lock.acquire()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock.acquire).912913> **Примечание**914>915> На macOS это неотличимо от [`Semaphore`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Semaphore), так как `sem_getvalue()` не реализован на этой платформе.916917#### `class multiprocessing.Condition([lock])`918919Условная переменная: псевдоним для [`threading.Condition`](https://python-all.ru/3.11/library/threading.html#threading.Condition).920921Если указана *блокировка*, то она должна быть объектом [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) или [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock) из [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing).922923Изменено в версии 3.3: Был добавлен метод [`wait_for()`](https://python-all.ru/3.11/library/threading.html#threading.Condition.wait_for).924925#### `class multiprocessing.Event`926927Клон [`threading.Event`](https://python-all.ru/3.11/library/threading.html#threading.Event).928929#### `class multiprocessing.Lock`930931Нерекурсивный объект блокировки: близкий аналог [`threading.Lock`](https://python-all.ru/3.11/library/threading.html#threading.Lock). Когда процесс или поток захватывает блокировку, последующие попытки захватить её из любого процесса или потока будут блокироваться до её освобождения; любой процесс или поток может её освободить. Концепции и поведение [`threading.Lock`](https://python-all.ru/3.11/library/threading.html#threading.Lock) применительно к потокам воспроизводятся здесь в [`multiprocessing.Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) применительно к процессам или потокам, за исключением отмеченных случаев.932933Обратите внимание, что [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) на самом деле является фабричной функцией, которая возвращает экземпляр `multiprocessing.synchronize.Lock`, инициализированный контекстом по умолчанию.934935[`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) поддерживает протокол [менеджера контекста](https://python-all.ru/3.11/glossary.html#term-context-manager) и поэтому может использоваться в операторах [`with`](https://python-all.ru/3.11/reference/compound_stmts.html#with).936937#### `acquire(block=True, timeout=None)`938939Захватывает блокировку, блокирующую или неблокирующую.940941Если аргумент *block* установлен в `True` (по умолчанию), вызов метода будет блокироваться, пока блокировка не окажется в разблокированном состоянии, затем установит её в заблокированное состояние и вернёт `True`. Обратите внимание, что имя этого первого аргумента отличается от имени в [`threading.Lock.acquire()`](https://python-all.ru/3.11/library/threading.html#threading.Lock.acquire).942943Если аргумент *block* установлен в `False`, вызов метода не блокируется. Если блокировка в данный момент находится в заблокированном состоянии, возвращается `False`; в противном случае блокировка устанавливается в заблокированное состояние и возвращается `True`.944945При вызове с положительным значением с плавающей точкой для *timeout* блокировка выполняется не дольше числа секунд, указанного в *timeout*, пока блокировку не удастся захватить. Вызовы с отрицательным значением *timeout* эквивалентны *timeout*, равному нулю. Вызовы со значением *timeout* равным `None` (по умолчанию) устанавливают бесконечный период ожидания. Обратите внимание, что обработка отрицательных или `None` значений для *timeout* отличается от реализованного поведения в [`threading.Lock.acquire()`](https://python-all.ru/3.11/library/threading.html#threading.Lock.acquire). Аргумент *timeout* не имеет практического значения, если аргумент *block* установлен в `False`, и поэтому игнорируется. Возвращает `True`, если блокировка была захвачена, или `False`, если период ожидания истёк.946947#### `release()`948949Освобождает блокировку. Может вызываться из любого процесса или потока, а не только из того, который изначально захватил блокировку.950951Поведение аналогично [`threading.Lock.release()`](https://python-all.ru/3.11/library/threading.html#threading.Lock.release) за исключением того, что при вызове на незаблокированной блокировке возбуждается [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError).952953#### `class multiprocessing.RLock`954955Объект рекурсивной блокировки: близкий аналог [`threading.RLock`](https://python-all.ru/3.11/library/threading.html#threading.RLock). Рекурсивная блокировка должна быть освобождена тем же процессом или потоком, который её захватил. После того как процесс или поток захватил рекурсивную блокировку, тот же процесс или поток может захватить её снова без блокировки; этот процесс или поток должен освободить её по одному разу за каждый захват.956957Обратите внимание, что [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock) на самом деле является фабричной функцией, которая возвращает экземпляр `multiprocessing.synchronize.RLock`, инициализированный контекстом по умолчанию.958959[`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock) поддерживает протокол [менеджера контекста](https://python-all.ru/3.11/glossary.html#term-context-manager) и поэтому может использоваться в операторах [`with`](https://python-all.ru/3.11/reference/compound_stmts.html#with).960961#### `acquire(block=True, timeout=None)`962963Захватывает блокировку, блокирующую или неблокирующую.964965При вызове с аргументом *block*, установленным в `True`, блокируется до тех пор, пока блокировка не окажется в разблокированном состоянии (не принадлежит ни одному процессу или потоку), если только блокировка уже не принадлежит текущему процессу или потоку. Затем текущий процесс или поток получает владение блокировкой (если ещё не владеет ею), и уровень рекурсии внутри блокировки увеличивается на единицу, возвращая значение `True`. Обратите внимание, что имеется несколько различий в поведении этого первого аргумента по сравнению с реализацией [`threading.RLock.acquire()`](https://python-all.ru/3.11/library/threading.html#threading.RLock.acquire), начиная с названия самого аргумента.966967При вызове с аргументом *block*, установленным в `False`, не блокируется. Если блокировка уже была захвачена (и, следовательно, принадлежит) другим процессом или потоком, текущий процесс или поток не получает владение, а уровень рекурсии внутри блокировки не изменяется, возвращая значение `False`. Если блокировка находится в разблокированном состоянии, текущий процесс или поток получает владение, а уровень рекурсии увеличивается, возвращая значение `True`.968969Использование и поведение аргумента *timeout* такие же, как в [`Lock.acquire()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock.acquire). Обратите внимание, что некоторые из этих особенностей *timeout* отличаются от реализованного поведения в [`threading.RLock.acquire()`](https://python-all.ru/3.11/library/threading.html#threading.RLock.acquire).970971#### `release()`972973Освобождает блокировку, уменьшая уровень рекурсии. Если после уменьшения уровень рекурсии становится нулевым, переводит блокировку в разблокированное состояние (не принадлежит ни одному процессу или потоку), и если какие-либо другие процессы или потоки ожидают разблокировки, позволяет ровно одному из них продолжить. Если после уменьшения уровень рекурсии всё ещё ненулевой, блокировка остаётся заблокированной и принадлежащей вызывающему процессу или потоку.974975Вызывайте этот метод только когда вызывающий процесс или поток владеет блокировкой. Исключение [`AssertionError`](https://python-all.ru/3.11/library/exceptions.html#AssertionError) возбуждается, если этот метод вызывается процессом или потоком, не являющимся владельцем, или если блокировка находится в разблокированном (непринадлежащем) состоянии. Обратите внимание, что тип возбуждаемого исключения в этой ситуации отличается от реализованного поведения в [`threading.RLock.release()`](https://python-all.ru/3.11/library/threading.html#threading.RLock.release).976977#### `class multiprocessing.Semaphore([value])`978979Объект семафора: близкий аналог [`threading.Semaphore`](https://python-all.ru/3.11/library/threading.html#threading.Semaphore).980981Имеется единственное отличие от его близкого аналога: первый аргумент метода `acquire` называется *block*, что согласуется с [`Lock.acquire()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock.acquire).982983> **Примечание**984>985> На macOS `sem_timedwait` не поддерживается, поэтому вызов `acquire()` с тайм-аутом будет эмулировать поведение этой функции с помощью цикла ожидания.986987> **Примечание**988>989> Если сигнал SIGINT, сгенерированный `Ctrl-C`, поступает, когда главный поток блокирован вызовом `BoundedSemaphore.acquire()`, [`Lock.acquire()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock.acquire), [`RLock.acquire()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock.acquire), `Semaphore.acquire()`, `Condition.acquire()` или `Condition.wait()`, то вызов будет немедленно прерван и возбуждено [`KeyboardInterrupt`](https://python-all.ru/3.11/library/exceptions.html#KeyboardInterrupt).990>991> Это отличается от поведения [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading), где SIGINT игнорируется, пока выполняются эквивалентные блокирующие вызовы.992993> **Примечание**994>995> Некоторые функции этого пакета требуют работающей реализации общего семафора в операционной системе. При её отсутствии модуль `multiprocessing.synchronize` будет отключён, а попытки импортировать его приведут к [`ImportError`](https://python-all.ru/3.11/library/exceptions.html#ImportError). См. [bpo-3770](https://python-all.ru/3.11/library/multiprocessing.html) для получения дополнительной информации.996997### Общие [`ctypes`](https://python-all.ru/3.11/library/ctypes.html#module-ctypes) объекты998999Можно создавать общие объекты с помощью разделяемой памяти, которые могут наследоваться дочерними процессами.10001001#### `multiprocessing.Value(typecode_or_type, *args, lock=True)`10021003Возвращает объект [`ctypes`](https://python-all.ru/3.11/library/ctypes.html#module-ctypes), выделенный из разделяемой памяти. По умолчанию возвращаемое значение на самом деле является синхронизированной обёрткой для объекта. Сам объект можно получить через атрибут *value* объекта [`Value`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Value).10041005*typecode\_or\_type* определяет тип возвращаемого объекта: это либо тип ctypes, либо однобуквенный код типа, используемый модулем [`array`](https://python-all.ru/3.11/library/array.html#module-array). *\*args* передаётся конструктору типа.10061007Если *блокировка* равна `True` (по умолчанию), то создаётся новый рекурсивный объект блокировки для синхронизации доступа к значению. Если *блокировка* является объектом [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) или [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock), то она будет использоваться для синхронизации доступа к значению. Если *блокировка* равна `False`, то доступ к возвращаемому объекту не будет автоматически защищён блокировкой, поэтому он не обязательно будет "процессобезопасным".10081009Операции, подобные `+=`, которые включают чтение и запись, не являются атомарными. Поэтому, если, например, требуется атомарно увеличить разделяемое значение, недостаточно просто сделать10101011```python1012counter.value += 11013```10141015При условии, что связанная блокировка рекурсивна (по умолчанию она такой и является), можно вместо этого сделать10161017```python1018with counter.get_lock():1019    counter.value += 11020```10211022Обратите внимание, что *блокировка* – это аргумент, передаваемый только по ключевому слову.10231024#### `multiprocessing.Array(typecode_or_type, size_or_initializer, *, lock=True)`10251026Возвращает массив ctypes, выделенный из разделяемой памяти. По умолчанию возвращаемое значение на самом деле является синхронизированной обёрткой для массива.10271028*typecode\_or\_type* определяет тип элементов возвращаемого массива: это либо ctypes-тип, либо однобуквенный код типа, используемый модулем [`array`](https://python-all.ru/3.11/library/array.html#module-array). Если *size\_or\_initializer* – целое число, то оно определяет длину массива, и массив будет заполнен нулями. В противном случае *size\_or\_initializer* – это последовательность, которая используется для инициализации массива, и её длина определяет длину массива.10291030Если *блокировка* равен `True` (по умолчанию), создаётся новый объект блокировки для синхронизации доступа к значению. Если *блокировка* – объект [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) или [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock), то он будет использоваться для синхронизации доступа к значению. Если *блокировка* равен `False`, доступ к возвращаемому объекту не будет автоматически защищён блокировкой, поэтому он не обязательно будет «процесс-безопасным».10311032Обратите внимание, что *блокировка* – это аргумент, передаваемый только по ключевому слову.10331034Обратите внимание, что массив типа [`ctypes.c_char`](https://python-all.ru/3.11/library/ctypes.html#ctypes.c_char) имеет атрибуты *value* и *raw*, которые позволяют использовать его для хранения и извлечения строк.10351036#### Модуль [`multiprocessing.sharedctypes`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.sharedctypes)10371038Модуль [`multiprocessing.sharedctypes`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.sharedctypes) предоставляет функции для выделения объектов [`ctypes`](https://python-all.ru/3.11/library/ctypes.html#module-ctypes) из разделяемой памяти, которые могут быть унаследованы дочерними процессами.10391040> **Примечание**1041>1042> Хотя можно сохранить указатель в разделяемой памяти, следует помнить, что он будет ссылаться на местоположение в адресном пространстве конкретного процесса. Однако указатель, скорее всего, будет недействительным в контексте второго процесса, и попытка разыменования указателя из второго процесса может привести к аварийному завершению.10431044#### `multiprocessing.sharedctypes.RawArray(typecode_or_type, size_or_initializer)`10451046Возвращает массив ctypes, выделенный из разделяемой памяти.10471048*typecode\_or\_type* определяет тип элементов возвращаемого массива: это либо тип ctypes, либо однобуквенный код типа, используемый модулем [`array`](https://python-all.ru/3.11/library/array.html#module-array). Если *size\_or\_initializer* – целое число, то оно определяет длину массива, и массив будет изначально заполнен нулями. В противном случае *size\_or\_initializer* – это последовательность, которая используется для инициализации массива, и её длина определяет длину массива.10491050Обратите внимание, что установка и получение элемента потенциально неатомарны – используйте вместо этого [`Array()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.sharedctypes.Array), чтобы гарантировать автоматическую синхронизацию доступа с помощью блокировки.10511052#### `multiprocessing.sharedctypes.RawValue(typecode_or_type, *args)`10531054Возвращает объект ctypes, выделенный из разделяемой памяти.10551056*typecode\_or\_type* определяет тип возвращаемого объекта: это либо тип ctypes, либо однобуквенный код типа, используемый модулем [`array`](https://python-all.ru/3.11/library/array.html#module-array). *\*args* передаётся конструктору типа.10571058Обратите внимание, что установка и получение значения потенциально неатомарны – используйте вместо этого [`Value()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.sharedctypes.Value), чтобы гарантировать автоматическую синхронизацию доступа с помощью блокировки.10591060Обратите внимание, что массив [`ctypes.c_char`](https://python-all.ru/3.11/library/ctypes.html#ctypes.c_char) имеет атрибуты `value` и `raw`, которые позволяют использовать его для сохранения и извлечения строк – см. документацию к [`ctypes`](https://python-all.ru/3.11/library/ctypes.html#module-ctypes).10611062#### `multiprocessing.sharedctypes.Array(typecode_or_type, size_or_initializer, *, lock=True)`10631064То же, что и [`RawArray()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.sharedctypes.RawArray), за исключением того, что в зависимости от значения *блокировка* может возвращаться процессобезопасная синхронизирующая обёртка вместо необработанного массива ctypes.10651066Если *блокировка* равна `True` (по умолчанию), то создаётся новый объект блокировки для синхронизации доступа к значению. Если *блокировка* является объектом [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) или [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock), то она будет использоваться для синхронизации доступа к значению. Если *блокировка* равна `False`, то доступ к возвращаемому объекту не будет автоматически защищён блокировкой, поэтому он не обязательно будет "процессобезопасным".10671068Обратите внимание, что *блокировка* – это аргумент, передаваемый только по ключевому слову.10691070#### `multiprocessing.sharedctypes.Value(typecode_or_type, *args, lock=True)`10711072То же, что и [`RawValue()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.sharedctypes.RawValue), за исключением того, что в зависимости от значения *блокировка* может возвращаться процессобезопасная синхронизирующая обёртка вместо необработанного объекта ctypes.10731074Если *блокировка* равен `True` (по умолчанию), создаётся новый объект блокировки для синхронизации доступа к значению. Если *блокировка* – объект [`Lock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Lock) или [`RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock), то он будет использоваться для синхронизации доступа к значению. Если *блокировка* равен `False`, доступ к возвращаемому объекту не будет автоматически защищён блокировкой, поэтому он не обязательно будет «процесс-безопасным».10751076Обратите внимание, что *блокировка* – это аргумент, передаваемый только по ключевому слову.10771078#### `multiprocessing.sharedctypes.copy(obj)`10791080Возвращает объект ctypes, выделенный в общей памяти и являющийся копией объекта ctypes *obj*.10811082#### `multiprocessing.sharedctypes.synchronized(obj[, lock])`10831084Возвращает процесс-безопасную обёртку для объекта ctypes, которая использует *блокировка* для синхронизации доступа. Если *блокировка* равен `None` (по умолчанию), объект [`multiprocessing.RLock`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.RLock) создаётся автоматически.10851086Синхронизированная обёртка будет иметь два дополнительных метода (помимо методов обёрнутого объекта): `get_obj()` возвращает обёрнутый объект, а `get_lock()` – объект блокировки, используемый для синхронизации.10871088Обратите внимание, что доступ к объекту ctypes через обёртку может быть значительно медленнее, чем доступ к исходному объекту ctypes.10891090Изменено в версии 3.5: Синхронизированные объекты поддерживают протокол [контекстного менеджера](https://python-all.ru/3.11/glossary.html#term-context-manager).10911092В таблице ниже сравнивается синтаксис создания разделяемых объектов ctypes из общей памяти с обычным синтаксисом ctypes. (В таблице `MyStruct` – это некоторый подкласс [`ctypes.Structure`](https://python-all.ru/3.11/library/ctypes.html#ctypes.Structure).)10931094| ctypes | sharedctypes с типом | sharedctypes с typecode |1095| --- | --- | --- |1096| c\_double(2.4) | RawValue(c\_double, 2.4) | RawValue(‘d’, 2.4) |1097| MyStruct(4, 6) | RawValue(MyStruct, 4, 6) |  |1098| (c\_short \* 7)() | RawArray(c\_short, 7) | RawArray(‘h’, 7) |1099| (c\_int \* 3)(9, 2, 8) | RawArray(c\_int, (9, 2, 8)) | RawArray(‘i’, (9, 2, 8)) |11001101Ниже приведён пример, в котором дочерний процесс изменяет несколько объектов ctypes:11021103```python1104from multiprocessing import Process, Lock1105from multiprocessing.sharedctypes import Value, Array1106from ctypes import Structure, c_double11071108class Point(Structure):1109    _fields_ = [('x', c_double), ('y', c_double)]11101111def modify(n, x, s, A):1112    n.value **= 21113    x.value **= 21114    s.value = s.value.upper()1115    for a in A:1116        a.x **= 21117        a.y **= 211181119if __name__ == '__main__':1120    lock = Lock()11211122    n = Value('i', 7)1123    x = Value(c_double, 1.0/3.0, lock=False)1124    s = Array('c', b'hello world', lock=lock)1125    A = Array(Point, [(1.875,-6.25), (-5.75,2.0), (2.375,9.5)], lock=lock)11261127    p = Process(target=modify, args=(n, x, s, A))1128    p.start()1129    p.join()11301131    print(n.value)1132    print(x.value)1133    print(s.value)1134    print([(a.x, a.y) for a in A])1135```11361137Выводятся следующие результаты:11381139```text11404911410.11111111111111111142HELLO WORLD1143[(3.515625, 39.0625), (33.0625, 4.0), (5.640625, 90.25)]1144```11451146### Менеджеры11471148Менеджеры предоставляют способ создания данных, которыми можно обмениваться между разными процессами, в том числе по сети между процессами, выполняющимися на разных машинах. Объект менеджера управляет серверным процессом, который управляет *разделяемыми объектами*. Другие процессы могут получать доступ к разделяемым объектам через прокси.11491150#### `multiprocessing.Manager()`11511152Возвращает запущенный объект [`SyncManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.SyncManager), который можно использовать для совместного использования объектов между процессами. Возвращаемый объект менеджера соответствует порождённому дочернему процессу и имеет методы, которые создают разделяемые объекты и возвращают соответствующие прокси.11531154Процессы менеджера завершаются, как только они будут собраны сборщиком мусора или завершится их родительский процесс. Классы менеджера определены в модуле [`multiprocessing.managers`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.managers):11551156#### `class multiprocessing.managers.BaseManager(address=None, authkey=None, serializer='pickle', ctx=None, *, shutdown_timeout=1.0)`11571158Создает объект BaseManager.11591160После создания необходимо вызвать [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.start) или `get_server().serve_forever()`, чтобы объект менеджера ссылался на запущенный процесс менеджера.11611162*address* – адрес, на котором процесс менеджера ожидает новые подключения. Если *address* равно `None`, то выбирается произвольный адрес.11631164*authkey* – ключ аутентификации, который будет использоваться для проверки подлинности входящих подключений к серверному процессу. Если *authkey* равно `None`, используется `current_process().authkey`. В противном случае используется *authkey*, и он должен быть байтовой строкой.11651166*serializer* должен быть `'pickle'` (использовать сериализацию [`pickle`](https://python-all.ru/3.11/library/pickle.html#module-pickle)) или `'xmlrpclib'` (использовать сериализацию [`xmlrpc.client`](https://python-all.ru/3.11/library/xmlrpc.client.html#module-xmlrpc.client)).11671168*ctx* – это объект контекста или `None` (используется текущий контекст). См. функцию `get_context()`.11691170*shutdown\_timeout* – тайм-аут в секундах, который используется для ожидания завершения процесса, используемого менеджером, в методе [`shutdown()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.shutdown). Если тайм-аут истекает, процесс завершается. Если завершение процесса также истекает по тайм-ауту, процесс уничтожается.11711172Изменено в версии 3.11: Добавлен параметр *shutdown\_timeout*.11731174#### `start([initializer[, initargs]])`11751176Запускает подпроцесс для запуска менеджера. Если *initializer* не равно `None`, то подпроцесс вызовет `initializer(*initargs)` при запуске.11771178#### `get_server()`11791180Возвращает объект `Server`, представляющий реальный сервер, управляемый менеджером. Объект `Server` поддерживает метод `serve_forever()`:11811182```python1183>>> from multiprocessing.managers import BaseManager1184>>> manager = BaseManager(address=('', 50000), authkey=b'abc')1185>>> server = manager.get_server()1186>>> server.serve_forever()1187```11881189`Server` также имеет атрибут [`address`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.address).11901191#### `connect()`11921193Подключает локальный объект менеджера к удаленному процессу менеджера:11941195```python1196>>> from multiprocessing.managers import BaseManager1197>>> m = BaseManager(address=('127.0.0.1', 50000), authkey=b'abc')1198>>> m.connect()1199```12001201#### `shutdown()`12021203Останавливает процесс, используемый менеджером. Это доступно только если [`start()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.start) был использован для запуска серверного процесса.12041205Этот метод можно вызывать несколько раз.12061207#### `register(typeid[, callable[, proxytype[, exposed[, method_to_typeid[, create_method]]]]])`12081209Метод класса, который можно использовать для регистрации типа или вызываемого объекта в классе менеджера.12101211*typeid* – это «идентификатор типа», который используется для идентификации определенного типа разделяемого объекта. Должен быть строкой.12121213*callable* – это вызываемый объект, используемый для создания объектов для данного идентификатора типа. Если экземпляр менеджера будет подключен к серверу с помощью метода [`connect()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.connect), или если аргумент *create\_method* равен `False`, то этот параметр можно оставить как `None`.12141215*proxytype* – это подкласс [`BaseProxy`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy), который используется для создания прокси для разделяемых объектов с данным *typeid*. Если `None`, то класс прокси создается автоматически.12161217*exposed* используется для указания последовательности имен методов, к которым прокси для данного typeid должны иметь доступ через [`BaseProxy._callmethod()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy._callmethod). (Если *exposed* равно `None`, то вместо него используется `proxytype._exposed_`, если он существует.) Если список exposed не указан, то все «публичные методы» разделяемого объекта будут доступны. (Здесь «публичный метод» означает любой атрибут, у которого есть метод [`__call__()`](https://python-all.ru/3.11/reference/datamodel.html#object.__call__) и имя которого не начинается с `'_'`.)12181219*method\_to\_typeid* – это отображение, используемое для указания возвращаемого типа тех открытых методов, которые должны возвращать прокси. Оно отображает имена методов в строки typeid. (Если *method\_to\_typeid* равно `None`, то вместо него используется `proxytype._method_to_typeid_`, если он существует.) Если имя метода не является ключом этого отображения или отображение равно `None`, то объект, возвращаемый методом, будет скопирован по значению.12201221*create\_method* определяет, следует ли создать метод с именем *typeid*, который можно использовать, чтобы указать серверному процессу создать новый разделяемый объект и вернуть для него прокси. По умолчанию `True`.12221223Экземпляры [`BaseManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager) также имеют одно свойство только для чтения:12241225#### `address`12261227Адрес, используемый менеджером.12281229Изменено в версии 3.3: Объекты Manager поддерживают протокол управления контекстом – см. [Типы менеджеров контекста](https://python-all.ru/3.11/library/stdtypes.html#typecontextmanager). [`__enter__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__enter__) запускает серверный процесс (если он еще не запущен), а затем возвращает объект менеджера. [`__exit__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__exit__) вызывает [`shutdown()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.shutdown).12301231В предыдущих версиях [`__enter__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__enter__) не запускал серверный процесс менеджера, если он ещё не был запущен.12321233#### `class multiprocessing.managers.SyncManager`12341235Подкласс [`BaseManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager), который можно использовать для синхронизации процессов. Объекты этого типа возвращаются [`multiprocessing.Manager()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Manager).12361237Его методы создают и возвращают [объекты-прокси](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-proxy-objects) для ряда часто используемых типов данных, которые нужно синхронизировать между процессами. Сюда в первую очередь входят общие списки и словари.12381239#### `Barrier(parties[, action[, timeout]])`12401241Создать общий объект [`threading.Barrier`](https://python-all.ru/3.11/library/threading.html#threading.Barrier) и вернуть для него прокси.12421243Новое в версии 3.3.12441245#### `BoundedSemaphore([value])`12461247Создать общий объект [`threading.BoundedSemaphore`](https://python-all.ru/3.11/library/threading.html#threading.BoundedSemaphore) и вернуть для него прокси.12481249#### `Condition([lock])`12501251Создать общий объект [`threading.Condition`](https://python-all.ru/3.11/library/threading.html#threading.Condition) и вернуть прокси для него.12521253Если *блокировка* предоставлена, то она должна быть прокси для объекта [`threading.Lock`](https://python-all.ru/3.11/library/threading.html#threading.Lock) или [`threading.RLock`](https://python-all.ru/3.11/library/threading.html#threading.RLock).12541255Изменено в версии 3.3: Был добавлен метод [`wait_for()`](https://python-all.ru/3.11/library/threading.html#threading.Condition.wait_for).12561257#### `Event()`12581259Создать общий объект [`threading.Event`](https://python-all.ru/3.11/library/threading.html#threading.Event) и вернуть прокси для него.12601261#### `Lock()`12621263Создать общий объект [`threading.Lock`](https://python-all.ru/3.11/library/threading.html#threading.Lock) и вернуть прокси для него.12641265#### `Namespace()`12661267Создать общий объект [`Namespace`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.Namespace) и вернуть прокси для него.12681269#### `Queue([maxsize])`12701271Создать общий объект [`queue.Queue`](https://python-all.ru/3.11/library/queue.html#queue.Queue) и вернуть прокси для него.12721273#### `RLock()`12741275Создать общий объект [`threading.RLock`](https://python-all.ru/3.11/library/threading.html#threading.RLock) и вернуть прокси для него.12761277#### `Semaphore([value])`12781279Создать общий объект [`threading.Semaphore`](https://python-all.ru/3.11/library/threading.html#threading.Semaphore) и вернуть прокси для него.12801281#### `Array(typecode, sequence)`12821283Создать массив и вернуть для него прокси.12841285#### `Value(typecode, value)`12861287Создать объект с атрибутом `value`, доступным для записи, и вернуть прокси для него.12881289#### `dict()`12901291#### `dict(mapping)`12921293#### `dict(sequence)`12941295Создать общий объект [`dict`](https://python-all.ru/3.11/library/stdtypes.html#dict) и вернуть прокси для него.12961297#### `list()`12981299#### `list(sequence)`13001301Создать общий объект [`list`](https://python-all.ru/3.11/library/stdtypes.html#list) и вернуть прокси для него.13021303Изменено в версии 3.6: Общие объекты могут быть вложенными. Например, общий объект-контейнер, такой как общий список, может содержать другие общие объекты, и все они будут управляться и синхронизироваться [`SyncManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.SyncManager).13041305#### `class multiprocessing.managers.Namespace`13061307Тип, который можно зарегистрировать с помощью [`SyncManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.SyncManager).13081309Объект пространства имён не имеет открытых методов, но имеет изменяемые атрибуты. Его представление показывает значения его атрибутов.13101311Однако при использовании прокси для объекта пространства имён атрибут, начинающийся с `'_'`, будет атрибутом прокси, а не атрибутом референта:13121313```pycon1314>>> manager = multiprocessing.Manager()1315>>> Global = manager.Namespace()1316>>> Global.x = 101317>>> Global.y = 'hello'1318>>> Global._z = 12.3    # это атрибут прокси1319>>> print(Global)1320Namespace(x=10, y='hello')1321```13221323#### Настраиваемые менеджеры13241325Чтобы создать собственный менеджер, создаётся подкласс [`BaseManager`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager) и используется метод класса [`register()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.register) для регистрации новых типов или вызываемых объектов в классе менеджера. Например:13261327```python1328from multiprocessing.managers import BaseManager13291330class MathsClass:1331    def add(self, x, y):1332        return x + y1333    def mul(self, x, y):1334        return x * y13351336class MyManager(BaseManager):1337    pass13381339MyManager.register('Maths', MathsClass)13401341if __name__ == '__main__':1342    with MyManager() as manager:1343        maths = manager.Maths()1344        print(maths.add(4, 3))         # выводит 71345        print(maths.mul(7, 8))         # выводит 561346```13471348#### Использование удалённого менеджера13491350Можно запустить сервер менеджера на одной машине и позволить клиентам использовать его с других машин (при условии, что соответствующие брандмауэры это разрешают).13511352Выполнение следующих команд создаёт сервер для одной общей очереди, к которой удалённые клиенты могут обращаться:13531354```python1355>>> from multiprocessing.managers import BaseManager1356>>> from queue import Queue1357>>> queue = Queue()1358>>> class QueueManager(BaseManager): pass1359>>> QueueManager.register('get_queue', callable=lambda:queue)1360>>> m = QueueManager(address=('', 50000), authkey=b'abracadabra')1361>>> s = m.get_server()1362>>> s.serve_forever()1363```13641365Один клиент может получить доступ к серверу следующим образом:13661367```python1368>>> from multiprocessing.managers import BaseManager1369>>> class QueueManager(BaseManager): pass1370>>> QueueManager.register('get_queue')1371>>> m = QueueManager(address=('foo.bar.org', 50000), authkey=b'abracadabra')1372>>> m.connect()1373>>> queue = m.get_queue()1374>>> queue.put('hello')1375```13761377Другой клиент также может использовать его:13781379```python1380>>> from multiprocessing.managers import BaseManager1381>>> class QueueManager(BaseManager): pass1382>>> QueueManager.register('get_queue')1383>>> m = QueueManager(address=('foo.bar.org', 50000), authkey=b'abracadabra')1384>>> m.connect()1385>>> queue = m.get_queue()1386>>> queue.get()1387'hello'1388```13891390Локальные процессы также могут получить доступ к этой очереди, используя приведённый выше код на клиенте для удалённого доступа к ней:13911392```python1393>>> from multiprocessing import Process, Queue1394>>> from multiprocessing.managers import BaseManager1395>>> class Worker(Process):1396...     def __init__(self, q):1397...         self.q = q1398...         super().__init__()1399...     def run(self):1400...         self.q.put('local hello')1401...1402>>> queue = Queue()1403>>> w = Worker(queue)1404>>> w.start()1405>>> class QueueManager(BaseManager): pass1406...1407>>> QueueManager.register('get_queue', callable=lambda: queue)1408>>> m = QueueManager(address=('', 50000), authkey=b'abracadabra')1409>>> s = m.get_server()1410>>> s.serve_forever()1411```14121413### Объекты-прокси14141415Прокси – это объект, который *ссылается* на общий объект, находящийся (предположительно) в другом процессе. Общий объект называется *референтом* этого прокси. Несколько объектов-прокси могут иметь один и тот же референт.14161417Объект-прокси имеет методы, которые вызывают соответствующие методы его референта (хотя не каждый метод референта обязательно будет доступен через прокси). Таким образом, прокси можно использовать так же, как и его референт:14181419```pycon1420>>> from multiprocessing import Manager1421>>> manager = Manager()1422>>> l = manager.list([i*i for i in range(10)])1423>>> print(l)1424[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]1425>>> print(repr(l))1426<ListProxy object, typeid 'list' at 0x...>1427>>> l[4]1428161429>>> l[2:5]1430[4, 9, 16]1431```14321433Обратите внимание, что применение [`str()`](https://python-all.ru/3.11/library/stdtypes.html#str) к прокси вернёт представление референта, тогда как применение [`repr()`](https://python-all.ru/3.11/library/functions.html#repr) вернёт представление прокси.14341435Важная особенность объектов-прокси – они сериализуемы (picklable), поэтому их можно передавать между процессами. Таким образом, референт может содержать [Объекты-прокси](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-proxy-objects). Это допускает вложение управляемых списков, словарей и других [Объектов-прокси](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-proxy-objects):14361437```pycon1438>>> a = manager.list()1439>>> b = manager.list()1440>>> a.append(b)         # референт a теперь содержит референт b1441>>> print(a, b)1442[<ListProxy object, typeid 'list' at ...>] []1443>>> b.append('hello')1444>>> print(a[0], b)1445['hello'] ['hello']1446```14471448Аналогично, прокси словарей и списков могут быть вложены друг в друга:14491450```python1451>>> l_outer = manager.list([ manager.dict() for i in range(2) ])1452>>> d_first_inner = l_outer[0]1453>>> d_first_inner['a'] = 11454>>> d_first_inner['b'] = 21455>>> l_outer[1]['c'] = 31456>>> l_outer[1]['z'] = 261457>>> print(l_outer[0])1458{'a': 1, 'b': 2}1459>>> print(l_outer[1])1460{'c': 3, 'z': 26}1461```14621463Если в референт входят стандартные (не прокси) объекты [`list`](https://python-all.ru/3.11/library/stdtypes.html#list) или [`dict`](https://python-all.ru/3.11/library/stdtypes.html#dict), изменения этих изменяемых значений не будут распространяться через менеджер, потому что прокси не может узнать, когда значения, содержащиеся внутри, изменяются. Однако сохранение значения в прокси-контейнере (что вызывает `__setitem__` на объекте-прокси) распространяется через менеджер, поэтому для эффективного изменения такого элемента можно присвоить изменённое значение обратно в прокси-контейнер:14641465```python1466# создать прокси для списка и добавить изменяемый объект (словарь)1467lproxy = manager.list()1468lproxy.append({})1469# теперь изменить словарь1470d = lproxy[0]1471d['a'] = 11472d['b'] = 21473# на данный момент изменения в d еще не синхронизированы, но при1474# обновлении словаря прокси уведомляется об изменении1475lproxy[0] = d1476```14771478Этот подход, возможно, менее удобен, чем использование вложенных [Объектов-прокси](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-proxy-objects) в большинстве случаев, но также демонстрирует степень контроля над синхронизацией.14791480> **Примечание**1481>1482> Типы прокси в [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) не поддерживают сравнение по значению. Так, например:1483>1484> ```pycon1485> >>> manager.list([1,2,3]) == [1,2,3]1486> False1487> ```1488>1489> При сравнении следует просто использовать копию референта.14901491#### `class multiprocessing.managers.BaseProxy`14921493Прокси-объекты являются экземплярами подклассов [`BaseProxy`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy).14941495#### `_callmethod(methodname[, args[, kwds]])`14961497Вызывает метод референта прокси и возвращает результат.14981499Если `proxy` – это прокси, чей референт – `obj`, то выражение15001501```python1502proxy._callmethod(methodname, args, kwds)1503```15041505вычислит выражение15061507```python1508getattr(obj, methodname)(*args, **kwds)1509```15101511в процессе менеджера.15121513Возвращаемое значение будет копией результата вызова или прокси для нового разделяемого объекта – см. документацию по аргументу *method\_to\_typeid* функции [`BaseManager.register()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseManager.register).15141515Если при вызове возникло исключение, то оно повторно возбуждается с помощью [`_callmethod()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy._callmethod). Если в процессе менеджера возникло другое исключение, то оно преобразуется в исключение `RemoteError` и возбуждается с помощью [`_callmethod()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy._callmethod).15161517Обратите внимание, что исключение будет возбуждаться, если *methodname* не был *экспонирован*.15181519Пример использования [`_callmethod()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.managers.BaseProxy._callmethod):15201521```pycon1522>>> l = manager.list(range(10))1523>>> l._callmethod('__len__')1524101525>>> l._callmethod('__getitem__', (slice(2, 7),)) # эквивалентно l[2:7]1526[2, 3, 4, 5, 6]1527>>> l._callmethod('__getitem__', (20,))          # эквивалентно l[20]1528Traceback (most recent call last):1529...1530IndexError: list index out of range1531```15321533#### `_getvalue()`15341535Возвращает копию референта.15361537Если референт не может быть сериализован (unpicklable), то это вызовет исключение.15381539#### `__repr__()`15401541Возвращает представление прокси-объекта.15421543#### `__str__()`15441545Возвращает представление референта.15461547#### Очистка15481549Прокси-объект использует колбэк слабой ссылки: когда он собирается сборщиком мусора, он отменяет свою регистрацию у менеджера, которому принадлежит его референт.15501551Разделяемый объект удаляется из процесса менеджера, когда на него больше не ссылается ни один прокси.15521553### Пулы процессов15541555Можно создать пул процессов, который будет выполнять задачи, отправленные ему с помощью класса [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool).15561557#### `class multiprocessing.pool.Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])`15581559Объект пула процессов, который управляет пулом рабочих процессов, которым можно отправлять задачи. Он поддерживает асинхронные результаты с тайм-аутами и колбэками, а также имеет параллельную реализацию map.15601561*processes* – количество используемых рабочих процессов. Если *processes* равно `None`, то используется число, возвращаемое [`os.cpu_count()`](https://python-all.ru/3.11/library/os.html#os.cpu_count).15621563Если *initializer* не равно `None`, то каждый рабочий процесс вызовет `initializer(*initargs)` при запуске.15641565*maxtasksperchild* – количество задач, которое рабочий процесс может выполнить до завершения и замены новым рабочим процессом, чтобы освободить неиспользуемые ресурсы. Значение по умолчанию *maxtasksperchild* равно `None`, что означает, что рабочие процессы будут жить столько же, сколько и пул.15661567*context* используется для указания контекста, в котором запускаются рабочие процессы. Обычно пул создаётся с помощью функции `multiprocessing.Pool()` или метода [`Pool()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool) объекта контекста. В обоих случаях *context* устанавливается соответствующим образом.15681569Обратите внимание, что методы объекта пула должны вызываться только тем процессом, который создал пул.15701571> **Предупреждение**1572>1573> Объекты [`multiprocessing.pool`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.pool) имеют внутренние ресурсы, которые необходимо должным образом управлять (как и любыми другими ресурсами): используйте пул как контекстный менеджер или вызывайте [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.close) и [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.terminate) вручную. Несоблюдение этого может привести к зависанию процесса при завершении.1574>1575> Обратите внимание, что **неправильно** полагаться на сборщик мусора для уничтожения пула, поскольку CPython не гарантирует вызов финализатора пула (см. [`object.__del__()`](https://python-all.ru/3.11/reference/datamodel.html#object.__del__) для получения дополнительной информации).15761577Изменено в версии 3.2: Добавлен параметр *maxtasksperchild*.15781579Изменено в версии 3.4: Добавлен параметр *context*.15801581> **Примечание**1582>1583> Рабочие процессы внутри [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool) обычно существуют в течение всего времени работы очереди пула. Часто используемый в других системах (например, Apache, mod\_wsgi и т.д.) подход для освобождения ресурсов, удерживаемых рабочими процессами, заключается в том, чтобы позволить рабочему процессу в пуле выполнить только определённый объём работы, после чего он завершается, очищается, и на его место запускается новый процесс. Аргумент *maxtasksperchild* функции [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool) предоставляет эту возможность конечному пользователю.15841585#### `apply(func[, args[, kwds]])`15861587Вызывает *func* с аргументами *args* и именованными аргументами *kwds*. Блокируется до получения результата. Поскольку этот метод блокируется, [`apply_async()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.apply_async) лучше подходит для параллельного выполнения работы. Кроме того, *func* выполняется только в одном из рабочих процессов пула.15881589#### `apply_async(func[, args[, kwds[, callback[, error_callback]]]])`15901591Вариант метода [`apply()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.apply), который возвращает объект [`AsyncResult`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.AsyncResult).15921593Если указан *колбэк*, то это должен быть вызываемый объект, принимающий один аргумент. Когда результат готов, к нему применяется *колбэк*, если только вызов не завершился ошибкой – в этом случае вместо него применяется *колбэк ошибки*.15941595Если указан *error\_callback*, то это должен быть вызываемый объект, принимающий один аргумент. Если целевая функция завершается ошибкой, то *error\_callback* вызывается с экземпляром исключения.15961597Колбэки должны завершаться немедленно, иначе поток, обрабатывающий результаты, будет заблокирован.15981599#### `map(func, iterable[, chunksize])`16001601Параллельный аналог встроенной функции [`map()`](https://python-all.ru/3.11/library/functions.html#map) (однако поддерживает только один аргумент *iterable*, для нескольких итерируемых объектов см. [`starmap()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.starmap)). Блокируется до получения результата.16021603Этот метод разбивает итерируемый объект на несколько частей (chunks), которые отправляет в пул процессов как отдельные задачи. Приблизительный размер этих частей можно задать, установив *chunksize* в положительное целое число.16041605Обратите внимание, что для очень длинных итерируемых объектов это может привести к высокому потреблению памяти. Для повышения эффективности рассмотрите возможность использования [`imap()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.imap) или [`imap_unordered()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.imap_unordered) с явным указанием *chunksize*.16061607#### `map_async(func, iterable[, chunksize[, callback[, error_callback]]])`16081609Вариант метода [`map()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map), который возвращает объект [`AsyncResult`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.AsyncResult).16101611Если указан *колбэк*, то это должен быть вызываемый объект, принимающий один аргумент. Когда результат готов, к нему применяется *колбэк*, если только вызов не завершился ошибкой – в этом случае вместо него применяется *колбэк ошибки*.16121613Если указан *error\_callback*, то это должен быть вызываемый объект, принимающий один аргумент. Если целевая функция завершается ошибкой, то *error\_callback* вызывается с экземпляром исключения.16141615Колбэки должны завершаться немедленно, иначе поток, обрабатывающий результаты, будет заблокирован.16161617#### `imap(func, iterable[, chunksize])`16181619Более ленивая версия [`map()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map).16201621Аргумент *chunksize* совпадает с тем, что используется в методе [`map()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map). Для очень длинных итерируемых объектов использование большого значения *chunksize* может привести к завершению задачи **значительно** быстрее, чем при использовании значения по умолчанию `1`.16221623Кроме того, если *chunksize* равно `1`, то метод `next()` итератора, возвращаемого методом [`imap()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.imap), имеет необязательный параметр *timeout*: `next(timeout)` возбудит [`multiprocessing.TimeoutError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.TimeoutError), если результат не может быть возвращён в течение *timeout* секунд.16241625#### `imap_unordered(func, iterable[, chunksize])`16261627То же, что и [`imap()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.imap), за исключением того, что порядок результатов из возвращаемого итератора считается произвольным. (Только когда есть только один рабочий процесс, порядок гарантированно будет «правильным».)16281629#### `starmap(func, iterable[, chunksize])`16301631Как и [`map()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map), за исключением того, что элементы *iterable* должны быть итерируемыми объектами, которые распаковываются в аргументы.16321633Таким образом, *iterable* из `[(1,2), (3, 4)]` приводит к `[func(1,2), func(3,4)]`.16341635Новое в версии 3.3.16361637#### `starmap_async(func, iterable[, chunksize[, callback[, error_callback]]])`16381639Комбинация [`starmap()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.starmap) и [`map_async()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map_async), которая перебирает *iterable* из итерируемых объектов и вызывает *func* с распакованными итерируемыми объектами. Возвращает объект результата.16401641Новое в версии 3.3.16421643#### `close()`16441645Предотвращает отправку новых задач в пул. После завершения всех задач рабочие процессы завершаются.16461647#### `terminate()`16481649Немедленно останавливает рабочие процессы, не дожидаясь завершения незаконченных задач. Когда объект пула будет собран сборщиком мусора, [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.terminate) будет вызван немедленно.16501651#### `join()`16521653Ожидает завершения рабочих процессов. Перед использованием [`join()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.join) необходимо вызвать [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.close) или [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.terminate).16541655Изменено в версии 3.3:Объекты пула теперь поддерживают протокол управления контекстом – см. [Context Manager Types](https://python-all.ru/3.11/library/stdtypes.html#typecontextmanager). [`__enter__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__enter__) возвращает объект пула, а [`__exit__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__exit__) вызывает [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.terminate).16561657#### `class multiprocessing.pool.AsyncResult`16581659Класс результата, возвращаемого [`Pool.apply_async()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.apply_async) и [`Pool.map_async()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.map_async).16601661#### `get([timeout])`16621663Возвращает результат, когда он будет получен. Если *timeout* не равен `None` и результат не поступает в течение *timeout* секунд, то вызывается [`multiprocessing.TimeoutError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.TimeoutError). Если удалённый вызов вызвал исключение, то это исключение будет повторно возбуждено [`get()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.AsyncResult.get).16641665#### `wait([timeout])`16661667Ожидает, пока результат не станет доступен или пока не пройдёт *timeout* секунд.16681669#### `ready()`16701671Возвращает, завершён ли вызов.16721673#### `successful()`16741675Возвращает, завершился ли вызов без возникновения исключения. Возбуждает [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError), если результат ещё не готов.16761677Изменено в версии 3.7:Если результат ещё не готов, [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError) возбуждается вместо [`AssertionError`](https://python-all.ru/3.11/library/exceptions.html#AssertionError).16781679Следующий пример демонстрирует использование пула:16801681```python1682from multiprocessing import Pool1683import time16841685def f(x):1686    return x*x16871688if __name__ == '__main__':1689    with Pool(processes=4) as pool:         # запустить 4 рабочих процесса1690        result = pool.apply_async(f, (10,)) # вычислить "f(10)" асинхронно в одном процессе1691        print(result.get(timeout=1))        # выводит "100", если компьютер не *очень* медленный16921693        print(pool.map(f, range(10)))       # выводит "[0, 1, 4,..., 81]"16941695        it = pool.imap(f, range(10))1696        print(next(it))                     # выводит "0"1697        print(next(it))                     # выводит "1"1698        print(it.next(timeout=1))           # выводит "4", если компьютер не *очень* медленный16991700        result = pool.apply_async(time.sleep, (10,))1701        print(result.get(timeout=1))        # вызывает multiprocessing.TimeoutError1702```17031704### Слушатели и клиенты17051706Обычно обмен сообщениями между процессами осуществляется с помощью очередей или объектов [`Connection`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection), возвращаемых [`Pipe()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Pipe).17071708Однако модуль [`multiprocessing.connection`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.connection) обеспечивает дополнительную гибкость. По сути, он предоставляет высокоуровневый API, ориентированный на сообщения, для работы с сокетами или именованными каналами Windows. Также поддерживается *аутентификация на основе дайджеста* с использованием модуля [`hmac`](https://python-all.ru/3.11/library/hmac.html#module-hmac) и опрос нескольких подключений одновременно.17091710#### `multiprocessing.connection.deliver_challenge(connection, authkey)`17111712Отправляет случайно сгенерированное сообщение на другой конец соединения и ожидает ответа.17131714Если ответ совпадает с дайджестом сообщения, используя *authkey* в качестве ключа, то на другой конец соединения отправляется приветственное сообщение. В противном случае возбуждается [`AuthenticationError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.AuthenticationError).17151716#### `multiprocessing.connection.answer_challenge(connection, authkey)`17171718Принимает сообщение, вычисляет дайджест сообщения, используя *authkey* в качестве ключа, а затем отправляет дайджест обратно.17191720Если приветственное сообщение не получено, то возбуждается [`AuthenticationError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.AuthenticationError).17211722#### `multiprocessing.connection.Client(address[, family[, authkey]])`17231724Пытается установить соединение с слушателем, использующим адрес *address*, возвращая [`Connection`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection).17251726Тип соединения определяется аргументом *family*, но его обычно можно опустить, поскольку он обычно определяется по формату *address*. (См. [Address Formats](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-address-formats))17271728Если *authkey* задан и не None, он должен быть байтовой строкой и будет использоваться как секретный ключ для проверки подлинности на основе HMAC. Если *authkey* равно None, аутентификация не выполняется. В случае неудачи аутентификации возбуждается исключение [`AuthenticationError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.AuthenticationError). См. [Ключи аутентификации](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-auth-keys).17291730#### `class multiprocessing.connection.Listener([address[, family[, backlog[, authkey]]]])`17311732Обёртка для привязанного сокета или именованного канала Windows, который «прослушивает» подключения.17331734*address* – это адрес, который будет использоваться привязанным сокетом или именованным каналом объекта слушателя.17351736> **Примечание**1737>1738> Если используется адрес ‘0.0.0.0’, он не будет доступной точкой подключения в Windows. Если требуется доступная точка подключения, следует использовать ‘127.0.0.1’.17391740*family* – тип используемого сокета (или именованного канала). Может быть одной из строк `'AF_INET'` (для TCP-сокета), `'AF_UNIX'` (для сокета домена Unix) или `'AF_PIPE'` (для именованного канала Windows). Из них гарантированно доступна только первая. Если *family* равно `None`, то семейство определяется по формату *address*. Если *address* также равно `None`, выбирается значение по умолчанию. По умолчанию выбирается семейство, которое считается самым быстрым из доступных. См. [Форматы адресов](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-address-formats). Обратите внимание: если *family* равно `'AF_UNIX'`, а address равен `None`, то сокет будет создан в частной временной директории, созданной с помощью [`tempfile.mkstemp()`](https://python-all.ru/3.11/library/tempfile.html#tempfile.mkstemp).17411742Если объект listener использует сокет, то *backlog* (по умолчанию 1) передаётся методу [`listen()`](https://python-all.ru/3.11/library/socket.html#socket.socket.listen) сокета после его привязки.17431744Если *authkey* задан и не None, он должен быть байтовой строкой и будет использоваться как секретный ключ для проверки подлинности на основе HMAC. Если *authkey* равно None, аутентификация не выполняется. В случае неудачи аутентификации возбуждается исключение [`AuthenticationError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.AuthenticationError). См. [Ключи аутентификации](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing-auth-keys).17451746#### `accept()`17471748Принимает соединение на привязанном сокете или именованном канале объекта listener и возвращает объект [`Connection`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection). Если предпринята попытка аутентификации и она не удалась, возбуждается [`AuthenticationError`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.AuthenticationError).17491750#### `close()`17511752Закрывает привязанный сокет или именованный канал объекта listener. Этот метод вызывается автоматически при сборке мусора listener'а. Однако рекомендуется вызывать его явно.17531754Объекты Listener имеют следующие свойства только для чтения:17551756#### `address`17571758Адрес, используемый объектом Listener.17591760#### `last_accepted`17611762Адрес, с которого поступило последнее принятое соединение. Если он недоступен, то равен `None`.17631764Изменено в версии 3.3: Объекты Listener теперь поддерживают протокол управления контекстом – см. [Типы менеджеров контекста](https://python-all.ru/3.11/library/stdtypes.html#typecontextmanager). [`__enter__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__enter__) возвращает объект listener, а [`__exit__()`](https://python-all.ru/3.11/library/stdtypes.html#contextmanager.__exit__) вызывает [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Listener.close).17651766#### `multiprocessing.connection.wait(object_list, timeout=None)`17671768Ожидает, пока объект из *object\_list* не будет готов. Возвращает список тех объектов из *object\_list*, которые готовы. Если *timeout* – число с плавающей точкой, вызов блокируется не более чем на указанное количество секунд. Если *timeout* равен `None`, блокировка будет неограниченной. Отрицательный тайм-аут эквивалентен нулевому.17691770Как в Unix, так и в Windows объект может появиться в *object\_list*, если он17711772- читаемый объект [`Connection`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection);1773- подключенный и читаемый объект [`socket.socket`](https://python-all.ru/3.11/library/socket.html#socket.socket); или1774- атрибут [`sentinel`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.sentinel) объекта [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process).17751776Объект соединения или сокета готов, когда из него доступны для чтения данные или другой конец был закрыт.17771778**Unix**: `wait(object_list, timeout)` почти эквивалентен `select.select(object_list, [], [], timeout)`. Разница в том, что если [`select.select()`](https://python-all.ru/3.11/library/select.html#select.select) прерван сигналом, он может возбудить [`OSError`](https://python-all.ru/3.11/library/exceptions.html#OSError) с кодом ошибки `EINTR`, тогда как [`wait()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.wait) этого не сделает.17791780**Windows**: Элемент в *object\_list* должен быть либо целочисленным дескриптором, который ожидаем (согласно определению из документации функции Win32 `WaitForMultipleObjects()`), либо объектом с методом [`fileno()`](https://python-all.ru/3.11/library/io.html#io.IOBase.fileno), возвращающим дескриптор сокета или канала. (Обратите внимание: дескрипторы каналов и сокетов **не** являются ожидаемыми дескрипторами.)17811782Новое в версии 3.3.17831784**Примеры**17851786Следующий серверный код создаёт listener, который использует `'secret password'` в качестве ключа аутентификации. Затем он ожидает соединения и отправляет некоторые данные клиенту:17871788```python1789from multiprocessing.connection import Listener1790from array import array17911792address = ('localhost', 6000)     # семейство определяется как 'AF_INET'17931794with Listener(address, authkey=b'secret password') as listener:1795    with listener.accept() as conn:1796        print('connection accepted from', listener.last_accepted)17971798        conn.send([2.25, None, 'junk', float])17991800        conn.send_bytes(b'hello')18011802        conn.send_bytes(array('i', [42, 1729]))1803```18041805Следующий код подключается к серверу и получает от него некоторые данные:18061807```python1808from multiprocessing.connection import Client1809from array import array18101811address = ('localhost', 6000)18121813with Client(address, authkey=b'secret password') as conn:1814    print(conn.recv())                  # => [2.25, None, 'junk', float]18151816    print(conn.recv_bytes())            # => 'hello'18171818    arr = array('i', [0, 0, 0, 0, 0])1819    print(conn.recv_bytes_into(arr))    # => 81820    print(arr)                          # => array('i', [42, 1729, 0, 0, 0])1821```18221823Следующий код использует [`wait()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.wait) для ожидания сообщений от нескольких процессов одновременно:18241825```python1826import time, random1827from multiprocessing import Process, Pipe, current_process1828from multiprocessing.connection import wait18291830def foo(w):1831    for i in range(10):1832        w.send((i, current_process().name))1833    w.close()18341835if __name__ == '__main__':1836    readers = []18371838    for i in range(4):1839        r, w = Pipe(duplex=False)1840        readers.append(r)1841        p = Process(target=foo, args=(w,))1842        p.start()1843        # Закрываем записывающий конец канала, чтобы убедиться, что1844        # p – единственный процесс, владеющий дескриптором канала. Это1845        # гарантирует, что когда p закроет свой дескриптор для записывающего конца,1846        # wait() немедленно сообщит, что читающий конец готов1847        w.close()18481849    while readers:1850        for r in wait(readers):1851            try:1852                msg = r.recv()1853            except EOFError:1854                readers.remove(r)1855            else:1856                print(msg)1857```18581859#### Форматы адресов18601861- Адрес `'AF_INET'` – это кортеж вида `(hostname, port)`, где *hostname* – строка, а *port* – целое число.1862- Адрес `'AF_UNIX'` – это строка, представляющая имя файла в файловой системе.1863- Адрес `'AF_PIPE'` – это строка вида `r'\\.\pipe\PipeName'`. Чтобы использовать [`Client()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Client) для подключения к именованному каналу на удалённом компьютере с именем *ServerName*, следует использовать адрес вида `r'\\ServerName\pipe\PipeName'`.18641865Обратите внимание: любая строка, начинающаяся с двух обратных слешей, по умолчанию считается адресом `'AF_PIPE'`, а не `'AF_UNIX'`.18661867### Ключи аутентификации18681869При использовании [`Connection.recv`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Connection.recv) полученные данные автоматически распиковываются. К сожалению, распиковка данных из ненадёжного источника представляет угрозу безопасности. Поэтому [`Listener`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Listener) и [`Client()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.connection.Client) используют модуль [`hmac`](https://python-all.ru/3.11/library/hmac.html#module-hmac) для обеспечения дайджест-аутентификации.18701871Ключ аутентификации – это байтовая строка, которую можно рассматривать как пароль: после установления соединения обе стороны требуют доказательства, что другая сторона знает ключ аутентификации. (Демонстрация того, что обе стороны используют один и тот же ключ, **не** предполагает отправку ключа по соединению.)18721873Если запрошена аутентификация, но ключ аутентификации не указан, то используется возвращаемое значение `current_process().authkey` (см. [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process)). Это значение автоматически наследуется любым объектом [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), который создаёт текущий процесс. Это означает, что (по умолчанию) все процессы многопроцессной программы используют один ключ аутентификации, который можно применять для настройки соединений между ними.18741875Подходящие ключи аутентификации также можно сгенерировать с помощью [`os.urandom()`](https://python-all.ru/3.11/library/os.html#os.urandom).18761877### Журналирование18781879Доступна поддержка журналирования. Однако обратите внимание, что пакет [`logging`](https://python-all.ru/3.11/library/logging.html#module-logging) не использует блокировки, разделяемые между процессами, поэтому сообщения от разных процессов могут перемешиваться (в зависимости от типа обработчика).18801881#### `multiprocessing.get_logger()`18821883Возвращает логгер, используемый модулем [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing). При необходимости создаётся новый.18841885При первом создании логгер имеет уровень [`logging.NOTSET`](https://python-all.ru/3.11/library/logging.html#logging.NOTSET) и не имеет обработчика по умолчанию. Сообщения, отправленные этому логгеру, по умолчанию не распространяются на корневой логгер.18861887Обратите внимание, что в Windows дочерние процессы наследуют только уровень логгера родительского процесса – любые другие настройки логгера не наследуются.18881889#### `multiprocessing.log_to_stderr(level=None)`18901891Эта функция выполняет вызов [`get_logger()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.get_logger), но в дополнение к возврату логгера, созданного функцией get\_logger, она добавляет обработчик, который отправляет вывод в [`sys.stderr`](https://python-all.ru/3.11/library/sys.html#sys.stderr), используя формат `'[%(levelname)s/%(processName)s] %(message)s'`. Можно изменить `levelname` логгера, передав аргумент `level`.18921893Ниже приведён пример сеанса с включённым журналированием:18941895```python1896>>> import multiprocessing, logging1897>>> logger = multiprocessing.log_to_stderr()1898>>> logger.setLevel(logging.INFO)1899>>> logger.warning('doomed')1900[WARNING/MainProcess] doomed1901>>> m = multiprocessing.Manager()1902[INFO/SyncManager-...] child process calling self.run()1903[INFO/SyncManager-...] created temp directory /.../pymp-...1904[INFO/SyncManager-...] manager serving at '/.../listener-...'1905>>> del m1906[INFO/MainProcess] sending shutdown message to manager1907[INFO/SyncManager-...] manager exiting with exitcode 01908```19091910Полную таблицу уровней журналирования см. в модуле [`logging`](https://python-all.ru/3.11/library/logging.html#module-logging).19111912### Модуль [`multiprocessing.dummy`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.dummy)19131914[`multiprocessing.dummy`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.dummy) воспроизводит API модуля [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing), но является не более чем обёрткой вокруг модуля [`threading`](https://python-all.ru/3.11/library/threading.html#module-threading).19151916В частности, функция `Pool`, предоставляемая модулем [`multiprocessing.dummy`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing.dummy), возвращает экземпляр [`ThreadPool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.ThreadPool), который является подклассом [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), поддерживающим все те же вызовы методов, но использующим пул рабочих потоков вместо рабочих процессов.19171918#### `class multiprocessing.pool.ThreadPool([processes[, initializer[, initargs]]])`19191920Объект пула потоков, который управляет пулом рабочих потоков, которым можно отправлять задачи. Экземпляры [`ThreadPool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.ThreadPool) полностью совместимы по интерфейсу с экземплярами [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), и их ресурсами необходимо правильно управлять – либо используя пул как контекстный менеджер, либо вызывая [`close()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.close) и [`terminate()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool.terminate) вручную.19211922*processes* – это количество используемых рабочих потоков. Если *processes* равно `None`, то используется число, возвращаемое [`os.cpu_count()`](https://python-all.ru/3.11/library/os.html#os.cpu_count).19231924Если *initializer* не равно `None`, то каждый рабочий процесс вызовет `initializer(*initargs)` при запуске.19251926В отличие от [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), *maxtasksperchild* и *context* не могут быть заданы.19271928> **Примечание**1929>1930> [`ThreadPool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.ThreadPool) имеет тот же интерфейс, что и [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool), который разработан вокруг пула процессов и появился до введения модуля [`concurrent.futures`](https://python-all.ru/3.11/library/concurrent.futures.html#module-concurrent.futures). Таким образом, он наследует некоторые операции, которые не имеют смысла для пула на основе потоков, и имеет собственный тип для представления статуса асинхронных задач – [`AsyncResult`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.AsyncResult), который не распознаётся другими библиотеками.1931>1932> Пользователям обычно следует отдавать предпочтение использованию [`concurrent.futures.ThreadPoolExecutor`](https://python-all.ru/3.11/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor), который имеет более простой интерфейс, изначально разработанный для потоков, и возвращает экземпляры [`concurrent.futures.Future`](https://python-all.ru/3.11/library/concurrent.futures.html#concurrent.futures.Future), совместимые со многими другими библиотеками, включая [`asyncio`](https://python-all.ru/3.11/library/asyncio.html#module-asyncio).19331934## Рекомендации по программированию19351936Существуют определённые рекомендации и идиомы, которых следует придерживаться при использовании [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing).19371938### Все методы запуска19391940Нижеследующее относится ко всем методам запуска.19411942Избегайте разделяемого состояния19431944> По возможности следует стараться избегать передачи больших объёмов данных между процессами.1945>1946> Вероятно, лучше всего ограничиться использованием очередей или каналов для связи между процессами, а не использовать низкоуровневые примитивы синхронизации.19471948Сериализуемость19491950> Убедитесь, что аргументы методов прокси-объектов сериализуемы.19511952Потокобезопасность прокси19531954> Не используйте прокси-объект из более чем одного потока, если не защищаете его блокировкой.1955>1956> (С разными процессами, использующими *один и тот же* прокси, проблем не возникает.)19571958Присоединение процессов-зомби19591960> В Unix, когда процесс завершается, но к нему не присоединились (joined), он становится зомби. Таких процессов не должно быть много, потому что каждый раз при запуске нового процесса (или вызове [`active_children()`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.active_children)) все завершённые процессы, к которым ещё не присоединились, будут присоединены. Кроме того, вызов [`Process.is_alive`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.is_alive) для завершённого процесса присоединяет его. Тем не менее, рекомендуется явно присоединять все запущенные процессы.19611962Лучше наследовать, чем упаковывать/распаковывать19631964> При использовании методов запуска *spawn* или *forkserver* многие типы из [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) должны быть упаковываемыми (picklable), чтобы дочерние процессы могли их использовать. Однако обычно следует избегать отправки разделяемых объектов другим процессам через каналы или очереди. Вместо этого стоит организовать программу так, чтобы процесс, которому требуется доступ к разделяемому ресурсу, созданному в другом месте, мог унаследовать его от родительского процесса.19651966Избегайте завершения процессов19671968> Использование метода [`Process.terminate`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.terminate) для остановки процесса может привести к тому, что любые разделяемые ресурсы (такие как блокировки, семафоры, каналы и очереди), которые в данный момент используются процессом, станут повреждёнными или недоступными для других процессов.1969>1970> Поэтому, вероятно, лучше рассматривать использование [`Process.terminate`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.terminate) только для процессов, которые никогда не используют разделяемые ресурсы.19711972Присоединение процессов, использующих очереди19731974> Имейте в виду, что процесс, поместивший элементы в очередь, будет ждать перед завершением, пока все буферизованные элементы не будут переданы потоком «feeder» в нижележащий канал. (Дочерний процесс может вызвать метод [`Queue.cancel_join_thread`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Queue.cancel_join_thread) очереди, чтобы избежать такого поведения.)1975>1976> Это означает, что при использовании очереди нужно убедиться, что все элементы, помещённые в очередь, будут в конечном итоге удалены до того, как процесс будет присоединён. В противном случае нельзя быть уверенным, что процессы, поместившие элементы в очередь, завершатся. Также помните, что недемонические процессы присоединяются автоматически.1977>1978> Пример, который приведёт к взаимоблокировке:1979>1980> ```python1981> from multiprocessing import Process, Queue1982>1983> def f(q):1984>     q.put('X' * 1000000)1985>1986> if __name__ == '__main__':1987>     queue = Queue()1988>     p = Process(target=f, args=(queue,))1989>     p.start()1990>     p.join()                    # это приводит к взаимоблокировке1991>     obj = queue.get()1992> ```1993>1994> Исправление заключается в замене двух последних строк местами (или просто удалении строки с `p.join()`).19951996Явная передача ресурсов дочерним процессам19971998> В Unix при использовании метода запуска *fork* дочерний процесс может использовать общий ресурс, созданный в родительском процессе с помощью глобального ресурса. Однако лучше передавать объект в качестве аргумента конструктору дочернего процесса.1999>2000> Помимо того, что это делает код (потенциально) совместимым с Windows и другими методами запуска, это также гарантирует, что пока дочерний процесс жив, объект не будет собран сборщиком мусора в родительском процессе. Это может быть важно, если некоторый ресурс освобождается при сборке мусора объекта в родительском процессе.2001>2002> Так, например2003>2004> ```python2005> from multiprocessing import Process, Lock2006>2007> def f():2008>     ... do something using "lock" ...2009>2010> if __name__ == '__main__':2011>     lock = Lock()2012>     for i in range(10):2013>         Process(target=f).start()2014> ```2015>2016> следует переписать как2017>2018> ```python2019> from multiprocessing import Process, Lock2020>2021> def f(l):2022>     ... do something using "l" ...2023>2024> if __name__ == '__main__':2025>     lock = Lock()2026>     for i in range(10):2027>         Process(target=f, args=(lock,)).start()2028> ```20292030Остерегайтесь замены [`sys.stdin`](https://python-all.ru/3.11/library/sys.html#sys.stdin) на «файлоподобный объект»20312032> [`multiprocessing`](https://python-all.ru/3.11/library/multiprocessing.html#module-multiprocessing) изначально безусловно вызывал:2033>2034> ```python2035> os.close(sys.stdin.fileno())2036> ```2037>2038> в методе `multiprocessing.Process._bootstrap()` – это приводило к проблемам с процессами внутри процессов. Теперь это изменено на:2039>2040> ```python2041> sys.stdin.close()2042> sys.stdin = open(os.open(os.devnull, os.O_RDONLY), closefd=False)2043> ```2044>2045> Это решает основную проблему столкновения процессов друг с другом, приводящую к ошибке неверного файлового дескриптора, но вносит потенциальную опасность для приложений, которые заменяют [`sys.stdin()`](https://python-all.ru/3.11/library/sys.html#sys.stdin) на «файлоподобный объект» с буферизацией вывода. Опасность в том, что если несколько процессов вызовут [`close()`](https://python-all.ru/3.11/library/io.html#io.IOBase.close) для этого файлоподобного объекта, одни и те же данные могут быть сброшены в объект несколько раз, что приведёт к повреждению.2046>2047> Если вы пишете файлоподобный объект и реализуете собственное кэширование, вы можете сделать его устойчивым к fork, сохраняя pid при каждом добавлении в кэш и сбрасывая кэш при изменении pid. Например:2048>2049> ```python2050> @property2051> def cache(self):2052>     pid = os.getpid()2053>     if pid != self._pid:2054>         self._pid = pid2055>         self._cache = []2056>     return self._cache2057> ```2058>2059> Для получения дополнительной информации см. [bpo-5155](https://python-all.ru/3.11/library/multiprocessing.html), [bpo-5313](https://python-all.ru/3.11/library/multiprocessing.html) и [bpo-5331](https://python-all.ru/3.11/library/multiprocessing.html)20602061### Методы запуска *spawn* и *forkserver*20622063Существует несколько дополнительных ограничений, которые не относятся к методу запуска *fork*.20642065Упаковываемость20662067> Убедитесь, что все аргументы `Process.__init__()` можно сериализовать с помощью pickle. Кроме того, если вы создаёте подкласс [`Process`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process), убедитесь, что экземпляры будут сериализуемы при вызове метода [`Process.start`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start).20682069Глобальные переменные20702071> Имейте в виду, что если код, выполняемый в дочернем процессе, попытается обратиться к глобальной переменной, то значение, которое он увидит (если оно есть), может не совпадать со значением в родительском процессе на момент вызова [`Process.start`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.Process.start).2072>2073> Однако глобальные переменные, которые представляют собой просто константы уровня модуля, не вызывают проблем.20742075Безопасный импорт главного модуля20762077> Необходимо убедиться, что главный модуль может быть безопасно импортирован новым интерпретатором Python без нежелательных побочных эффектов (например, запуска нового процесса).2078>2079> Например, при использовании методов запуска *spawn* или *forkserver* выполнение следующего модуля приведёт к ошибке [`RuntimeError`](https://python-all.ru/3.11/library/exceptions.html#RuntimeError):2080>2081> ```python2082> from multiprocessing import Process2083>2084> def foo():2085>     print('hello')2086>2087> p = Process(target=foo)2088> p.start()2089> ```2090>2091> Вместо этого следует защитить «точку входа» программы с помощью `if __name__ == '__main__':` следующим образом:2092>2093> ```python2094> from multiprocessing import Process, freeze_support, set_start_method2095>2096> def foo():2097>     print('hello')2098>2099> if __name__ == '__main__':2100>     freeze_support()2101>     set_start_method('spawn')2102>     p = Process(target=foo)2103>     p.start()2104> ```2105>2106> (Строку `freeze_support()` можно опустить, если программа будет запускаться обычным образом, а не как замороженное приложение.)2107>2108> Это позволяет только что порождённому интерпретатору Python безопасно импортировать модуль и затем выполнить функцию `foo()` этого модуля.2109>2110> Аналогичные ограничения действуют, если пул или менеджер создаются в главном модуле.21112112## Примеры21132114Демонстрация создания и использования настраиваемых менеджеров и прокси:21152116```python2117from multiprocessing import freeze_support2118from multiprocessing.managers import BaseManager, BaseProxy2119import operator21202121##21222123class Foo:2124    def f(self):2125        print('you called Foo.f()')2126    def g(self):2127        print('you called Foo.g()')2128    def _h(self):2129        print('you called Foo._h()')21302131# Простая функция-генератор2132def baz():2133    for i in range(10):2134        yield i*i21352136# Тип прокси для объектов-генераторов2137class GeneratorProxy(BaseProxy):2138    _exposed_ = ['__next__']2139    def __iter__(self):2140        return self2141    def __next__(self):2142        return self._callmethod('__next__')21432144# Функция для возврата модуля operator2145def get_operator_module():2146    return operator21472148##21492150class MyManager(BaseManager):2151    pass21522153# зарегистрировать класс Foo; сделать `f()` и `g()` доступными через прокси2154MyManager.register('Foo1', Foo)21552156# зарегистрировать класс Foo; сделать `g()` и `_h()` доступными через прокси2157MyManager.register('Foo2', Foo, exposed=('g', '_h'))21582159# зарегистрировать функцию-генератор baz; использовать `GeneratorProxy` для создания прокси2160MyManager.register('baz', baz, proxytype=GeneratorProxy)21612162# зарегистрировать get_operator_module(); сделать публичные функции доступными через прокси2163MyManager.register('operator', get_operator_module)21642165##21662167def test():2168    manager = MyManager()2169    manager.start()21702171    print('-' * 20)21722173    f1 = manager.Foo1()2174    f1.f()2175    f1.g()2176    assert not hasattr(f1, '_h')2177    assert sorted(f1._exposed_) == sorted(['f', 'g'])21782179    print('-' * 20)21802181    f2 = manager.Foo2()2182    f2.g()2183    f2._h()2184    assert not hasattr(f2, 'f')2185    assert sorted(f2._exposed_) == sorted(['g', '_h'])21862187    print('-' * 20)21882189    it = manager.baz()2190    for i in it:2191        print('<%d>' % i, end=' ')2192    print()21932194    print('-' * 20)21952196    op = manager.operator()2197    print('op.add(23, 45) =', op.add(23, 45))2198    print('op.pow(2, 94) =', op.pow(2, 94))2199    print('op._exposed_ =', op._exposed_)22002201##22022203if __name__ == '__main__':2204    freeze_support()2205    test()2206```22072208Использование [`Pool`](https://python-all.ru/3.11/library/multiprocessing.html#multiprocessing.pool.Pool):22092210```python2211import multiprocessing2212import time2213import random2214import sys22152216#2217# Функции, используемые тестовым кодом2218#22192220def calculate(func, args):2221    result = func(*args)2222    return '%s says that %s%s = %s' % (2223        multiprocessing.current_process().name,2224        func.__name__, args, result2225        )22262227def calculatestar(args):2228    return calculate(*args)22292230def mul(a, b):2231    time.sleep(0.5 * random.random())2232    return a * b22332234def plus(a, b):2235    time.sleep(0.5 * random.random())2236    return a + b22372238def f(x):2239    return 1.0 / (x - 5.0)22402241def pow3(x):2242    return x ** 322432244def noop(x):2245    pass22462247#2248# Тестовый код2249#22502251def test():2252    PROCESSES = 42253    print('Creating pool with %d processes\n' % PROCESSES)22542255    with multiprocessing.Pool(PROCESSES) as pool:2256        #2257        # Тесты2258        #22592260        TASKS = [(mul, (i, 7)) for i in range(10)] + \2261                [(plus, (i, 8)) for i in range(10)]22622263        results = [pool.apply_async(calculate, t) for t in TASKS]2264        imap_it = pool.imap(calculatestar, TASKS)2265        imap_unordered_it = pool.imap_unordered(calculatestar, TASKS)22662267        print('Ordered results using pool.apply_async():')2268        for r in results:2269            print('\t', r.get())2270        print()22712272        print('Ordered results using pool.imap():')2273        for x in imap_it:2274            print('\t', x)2275        print()22762277        print('Unordered results using pool.imap_unordered():')2278        for x in imap_unordered_it:2279            print('\t', x)2280        print()22812282        print('Ordered results using pool.map() --- will block till complete:')2283        for x in pool.map(calculatestar, TASKS):2284            print('\t', x)2285        print()22862287        #2288        # Тестирование обработки ошибок2289        #22902291        print('Testing error handling:')22922293        try:2294            print(pool.apply(f, (5,)))2295        except ZeroDivisionError:2296            print('\tGot ZeroDivisionError as expected from pool.apply()')2297        else:2298            raise AssertionError('expected ZeroDivisionError')22992300        try:2301            print(pool.map(f, list(range(10))))2302        except ZeroDivisionError:2303            print('\tGot ZeroDivisionError as expected from pool.map()')2304        else:2305            raise AssertionError('expected ZeroDivisionError')23062307        try:2308            print(list(pool.imap(f, list(range(10)))))2309        except ZeroDivisionError:2310            print('\tGot ZeroDivisionError as expected from list(pool.imap())')2311        else:2312            raise AssertionError('expected ZeroDivisionError')23132314        it = pool.imap(f, list(range(10)))2315        for i in range(10):2316            try:2317                x = next(it)2318            except ZeroDivisionError:2319                if i == 5:2320                    pass2321            except StopIteration:2322                break2323            else:2324                if i == 5:2325                    raise AssertionError('expected ZeroDivisionError')23262327        assert i == 92328        print('\tGot ZeroDivisionError as expected from IMapIterator.next()')2329        print()23302331        #2332        # Тестирование тайм-аутов2333        #23342335        print('Testing ApplyResult.get() with timeout:', end=' ')2336        res = pool.apply_async(calculate, TASKS[0])2337        while 1:2338            sys.stdout.flush()2339            try:2340                sys.stdout.write('\n\t%s' % res.get(0.02))2341                break2342            except multiprocessing.TimeoutError:2343                sys.stdout.write('.')2344        print()2345        print()23462347        print('Testing IMapIterator.next() with timeout:', end=' ')2348        it = pool.imap(calculatestar, TASKS)2349        while 1:2350            sys.stdout.flush()2351            try:2352                sys.stdout.write('\n\t%s' % it.next(0.02))2353            except StopIteration:2354                break2355            except multiprocessing.TimeoutError:2356                sys.stdout.write('.')2357        print()2358        print()23592360if __name__ == '__main__':2361    multiprocessing.freeze_support()2362    test()2363```23642365Пример использования очередей для передачи задач набору рабочих процессов и сбора результатов:23662367```python2368import time2369import random23702371from multiprocessing import Process, Queue, current_process, freeze_support23722373#2374# Функция, выполняемая рабочими процессами2375#23762377def worker(input, output):2378    for func, args in iter(input.get, 'STOP'):2379        result = calculate(func, args)2380        output.put(result)23812382#2383# Функция, используемая для вычисления результата2384#23852386def calculate(func, args):2387    result = func(*args)2388    return '%s says that %s%s = %s' % \2389        (current_process().name, func.__name__, args, result)23902391#2392# Функции, на которые ссылаются задачи2393#23942395def mul(a, b):2396    time.sleep(0.5*random.random())2397    return a * b23982399def plus(a, b):2400    time.sleep(0.5*random.random())2401    return a + b24022403#2404#2405#24062407def test():2408    NUMBER_OF_PROCESSES = 42409    TASKS1 = [(mul, (i, 7)) for i in range(20)]2410    TASKS2 = [(plus, (i, 8)) for i in range(10)]24112412    # Создание очередей2413    task_queue = Queue()2414    done_queue = Queue()24152416    # Отправка задач2417    for task in TASKS1:2418        task_queue.put(task)24192420    # Запуск рабочих процессов2421    for i in range(NUMBER_OF_PROCESSES):2422        Process(target=worker, args=(task_queue, done_queue)).start()24232424    # Получение и вывод результатов2425    print('Unordered results:')2426    for i in range(len(TASKS1)):2427        print('\t', done_queue.get())24282429    # Добавить ещё задач с помощью `put()`2430    for task in TASKS2:2431        task_queue.put(task)24322433    # Получить и вывести ещё несколько результатов2434    for i in range(len(TASKS2)):2435        print('\t', done_queue.get())24362437    # Сообщить дочерним процессам об остановке2438    for i in range(NUMBER_OF_PROCESSES):2439        task_queue.put('STOP')24402441if __name__ == '__main__':2442    freeze_support()2443    test()2444```2445