Ответ
Модуль multiprocessing в Python предлагает несколько механизмов для безопасного обмена данными между процессами (IPC - Inter-Process Communication), так как процессы по умолчанию не разделяют память и работают в изолированных адресных пространствах.
-
Очереди (
multiprocessing.Queue)- Описание: Потокобезопасная очередь, работающая по принципу FIFO (First-In, First-Out). Объекты перед помещением в очередь сериализуются (pickle).
- Сценарий: Идеально подходит для организации обмена сообщениями между несколькими процессами-производителями (producers) и процессами-потребителями (consumers).
from multiprocessing import Process, Queue
def worker(q): q.put('Hello from child process')
if name == 'main': q = Queue() p = Process(target=worker, args=(q,)) p.start() print(q.get()) # Вывод: Hello from child process p.join()
-
Каналы (
multiprocessing.Pipe)- Описание: Создает пару соединенных объектов
Connection, представляющих два конца канала. По умолчанию канал является двунаправленным. - Сценарий: Эффективен для двусторонней связи между двумя конкретными процессами.
from multiprocessing import Process, Pipe
def worker(conn): conn.send([42, None, 'hello']) conn.close()
if name == 'main': parent_conn, child_conn = Pipe() p = Process(target=worker, args=(child_conn,)) p.start() print(parent_conn.recv()) # Вывод: [42, None, 'hello'] p.join()
- Описание: Создает пару соединенных объектов
-
Разделяемая память (
ValueиArray)- Описание: Позволяет нескольким процессам совместно использовать и изменять одни и те же данные в памяти.
Valueдля одного значения,Arrayдля массива простых типов (числа, символы). - Сценарий: Самый быстрый способ обмена, так как избегает накладных расходов на сериализацию. Требует использования блокировок (
Lock) для предотвращения состояния гонки при одновременной записи.from multiprocessing import Process, Value, Array, Lock
def worker(n, a, lock): with lock: n.value += 1 for i in range(len(a)): a[i] = -a[i]
if name == 'main': lock = Lock() num = Value('d', 0.0) arr = Array('i', range(10)) p = Process(target=worker, args=(num, arr, lock)) p.start() p.join() print(num.value) # Вывод: 1.0 print(list(arr)) # Вывод: [0, -1, -2, ...]
- Описание: Позволяет нескольким процессам совместно использовать и изменять одни и те же данные в памяти.
| Механизм | Основной сценарий | Производительность | Сложность использования |
|---|---|---|---|
Queue |
Обмен сообщениями (многие-ко-многим) | Средняя | Низкая |
Pipe |
Двусторонняя связь (один-к-одному) | Высокая | Низкая |
Value/Array |
Общий доступ к простым данным | Очень высокая | Средняя (нужны блокировки) |
Ответ 18+ 🔞
Так, слушай сюда, про эти ваши процессы в питоне. Ну, типа, каждый процесс — это как отдельная квартира, понимаешь? Они друг про друга нихуя не знают и память у них разная. А нам надо, чтобы они общались, эти распиздяи. Ну, мультипроцессинг нам три штуки подкидывает, на выбор, как в столовке.
Первое — это очередь (Queue). Представь себе конвейер на заводе, куда один кидает детали, а другой снимает. FIFO, блядь, кто первый встал — того и тапки. Всё, что туда суёшь, оно сериализуется (это типа в архив запаковывается), потом распаковывается. Идеально, когда процессов дохуя и все друг другу что-то пишут.
from multiprocessing import Process, Queue
def работяга(q):
q.put('Привет из дочернего процесса, ёпта')
if __name__ == '__main__':
q = Queue()
p = Process(target=работяга, args=(q,))
p.start()
print(q.get()) # Выведет: Привет из дочернего процесса, ёпта
p.join()
Второе — каналы (Pipe). Это типа проводок от двух раций. Создаёшь парочку, один конец — себе, другой — соседу. И вы можете друг другу в них орать (точнее, данные слать). По умолчанию — двусторонние, можно и туда, и обратно.
from multiprocessing import Process, Pipe
def работяга(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
родитель_коннект, детский_коннект = Pipe()
p = Process(target=работяга, args=(детский_коннект,))
p.start()
print(родитель_коннект.recv()) # Выведет: [42, None, 'hello']
p.join()
Ну и третье, самое быстрое, но и самое опасное — разделяемая память (Value и Array). Это типа общий холодильник в коммуналке. Все процессы могут туда лезть и менять что хотят. Value — для одной переменной (число, строка), Array — для массива простых типов. Но тут, блядь, без блокировок (Lock) — пипец, состояние гонки обеспечено. Один пишет, другой в это же время стирает — и всё, каша.
from multiprocessing import Process, Value, Array, Lock
def работяга(n, a, lock):
with lock:
n.value += 1
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
lock = Lock()
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=работяга, args=(num, arr, lock))
p.start()
p.join()
print(num.value) # Выведет: 1.0
print(list(arr)) # Выведет: [0, -1, -2, ...]
Короче, табличка для тех, у кого мозг уже кипит:
| Штука | Для чего годится | Скорость | Сложность |
|---|---|---|---|
Queue |
Много процессов, обмен сообщениями | Средняя | Низкая (просто кидай и бери) |
Pipe |
Два процесса, быстрый диалог | Высокая | Низкая |
Value/Array |
Общая память, скорость критична | Очень высокая | Средняя (следи за блокировками!) |
Выбирай по обстановке, а то так и до deadlock'а недалеко, ёпта.