← Назад к вопросам

Зачем нужен процесс?

1.6 Junior🔥 71 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем нужен процесс в программировании

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

Что такое процесс

Процесс содержит:

  • Код программы (исполняемый файл)
  • Свою память (heap, stack, data segment)
  • Файловые дескрипторы (открытые файлы, сокеты)
  • Переменные окружения
  • PID (Process ID) — уникальный идентификатор
import os
import sys

print(f"Текущий PID: {os.getpid()}")
print(f"Parent PID: {os.getppid()}")
print(f"Имя процесса: {sys.argv[0]}")
print(f"Память процесса: ~{os.getpid()} байт")

1. Разделение ресурсов между независимыми программами

import os
from multiprocessing import Process

def worker(name, count):
    """Независимый процесс со своей памятью"""
    print(f"Worker {name} started (PID: {os.getpid()})")
    for i in range(count):
        print(f"Worker {name}: iteration {i}")
    print(f"Worker {name} finished")

if __name__ == '__main__':
    # Создать несколько независимых процессов
    p1 = Process(target=worker, args=("A", 3))
    p2 = Process(target=worker, args=("B", 3))
    
    print(f"Main process PID: {os.getpid()}")
    
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()
    
    print("All processes finished")

# Каждый процесс имеет свой PID и независимую память

2. Настоящий параллелизм (Multiprocessing)

В отличие от потоков, процессы работают параллельно на многоядерных системах:

import time
from multiprocessing import Process
import os

def cpu_intensive(n):
    """CPU-bound операция"""
    total = 0
    for i in range(n):
        total += i
    return total

def sequential_execution():
    """Последовательное выполнение"""
    start = time.time()
    cpu_intensive(100000000)
    cpu_intensive(100000000)
    print(f"Sequential: {time.time() - start:.2f}s")

def parallel_execution():
    """Параллельное выполнение в процессах"""
    start = time.time()
    p1 = Process(target=cpu_intensive, args=(100000000,))
    p2 = Process(target=cpu_intensive, args=(100000000,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(f"Parallel: {time.time() - start:.2f}s")

if __name__ == '__main__':
    sequential_execution()  # ~2.5 сек
    parallel_execution()    # ~1.3 сек (на 2 ядрах)

3. Изоляция и безопасность

Каждый процесс имеет собственное адресное пространство:

from multiprocessing import Process

global_var = 10  # Глобальная переменная в главном процессе

def modify_global():
    global global_var
    global_var = 20  # Изменит только в этом процессе
    print(f"В процессе: global_var = {global_var}")

if __name__ == '__main__':
    print(f"До: global_var = {global_var}")
    
    p = Process(target=modify_global)
    p.start()
    p.join()
    
    print(f"После: global_var = {global_var}")
    # Вывод: После: global_var = 10 (не изменилась!)

Это гарантирует изоляцию (важно для безопасности):

from multiprocessing import Process
import traceback

def crashing_process():
    raise Exception("Crash in worker process")

if __name__ == '__main__':
    try:
        p = Process(target=crashing_process)
        p.start()
        p.join()
        # Главный процесс не падает!
        print("Main process still alive")
    except Exception as e:
        print(f"Caught: {e}")
        traceback.print_exc()

4. Использование Process Pool для масштабирования

from multiprocessing import Pool
import time

def process_item(item):
    """Обработать один элемент"""
    time.sleep(1)  # Имитация работы
    return item ** 2

if __name__ == '__main__':
    items = list(range(10))
    
    # Последовательно
    start = time.time()
    results = [process_item(i) for i in items]
    print(f"Sequential: {time.time() - start:.2f}s")
    
    # Параллельно на 4 процессах
    start = time.time()
    with Pool(4) as pool:
        results = pool.map(process_item, items)
    print(f"Parallel (4 processes): {time.time() - start:.2f}s")
    
    print(f"Results: {results}")

5. Обработка больших объёмов данных

from multiprocessing import Pool
import os

def process_file_chunk(chunk_info):
    """Обработать часть файла в отдельном процессе"""
    file_path, start, end = chunk_info
    chunk_data = []
    
    with open(file_path, 'r') as f:
        f.seek(start)
        chunk = f.read(end - start)
        chunk_data = chunk.strip().split('\n')
    
    # Обработка
    processed = [line.upper() for line in chunk_data]
    return len(processed)

def process_large_file(file_path, num_processes=4):
    """Обработать большой файл параллельно"""
    file_size = os.path.getsize(file_path)
    chunk_size = file_size // num_processes
    
    chunks = [
        (file_path, i * chunk_size, (i + 1) * chunk_size)
        for i in range(num_processes)
    ]
    
    with Pool(num_processes) as pool:
        results = pool.map(process_file_chunk, chunks)
    
    return sum(results)

if __name__ == '__main__':
    # total_lines = process_large_file('large_file.txt')
    # print(f"Processed {total_lines} lines")
    pass

6. Долгоживущие фоновые процессы

from multiprocessing import Process
import time
import signal

def background_worker():
    """Фоновый процесс, работающий независимо"""
    try:
        while True:
            print("Background worker is running...")
            time.sleep(2)
    except KeyboardInterrupt:
        print("Background worker stopped")

if __name__ == '__main__':
    # Запустить фоновый процесс
    worker_process = Process(target=background_worker, daemon=True)
    worker_process.start()
    
    # Основная программа продолжает работу
    for i in range(5):
        print(f"Main process: {i}")
        time.sleep(1)
    
    print("Main process finished")
    # Daemon процесс автоматически завершится

7. Коммуникация между процессами (IPC)

from multiprocessing import Process, Queue, Pipe

# Использование Queue
def producer(queue):
    for i in range(5):
        queue.put(f"Item {i}")
        print(f"Produced: Item {i}")

def consumer(queue):
    while True:
        try:
            item = queue.get(timeout=1)
            print(f"Consumed: {item}")
        except:
            break

if __name__ == '__main__':
    q = Queue()
    
    p1 = Process(target=producer, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()

# Использование Pipe
def sender(conn):
    for i in range(3):
        conn.send(f"Message {i}")
    conn.close()

def receiver(conn):
    while True:
        try:
            msg = conn.recv()
            print(f"Received: {msg}")
        except EOFError:
            break

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    
    p1 = Process(target=sender, args=(child_conn,))
    p2 = Process(target=receiver, args=(parent_conn,))
    
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()

8. Когда использовать процессы

Процессы используют для:

  • CPU-bound операции (вычисления, обработка данных)
  • Параллельная работа на многоядерных системах
  • Долгоживущие фоновые задачи
  • Разделение работы между независимыми компонентами
  • Обработка больших файлов параллельно
  • Высокая надёжность (крах одного процесса не влияет на другие)

Процессы НЕ используют для:

  • I/O операции (используй async или threading)
  • Частое создание процессов (дорого)
  • Нужна частая общая память (используй threading или asyncio)

9. Сравнение: Process vs Thread vs Async

АспектProcessThreadAsync
ПараллелизмНастоящийПсевдопараллелизмКонкурентный
GILНетДа (ограничение)Нет
Память~50МБ~2МБ~1KB
CPU-boundОтличноПлохоПлохо
I/O boundOKOKОтлично
ИзоляцияПолнаяЧастичнаяПолная
СложностьВысокаяСредняяСредняя

Заключение

Процесс — это изолированный экземпляр программы с собственной памятью и ресурсами. Процессы необходимы для:

  • Настоящего параллелизма на многоядерных системах
  • CPU-bound операций
  • Высокой надёжности и изоляции
  • Долгоживущих фоновых задач

Основной недостаток — высокое потребление памяти и затраты на создание, поэтому для I/O операций лучше использовать async или threading.

Зачем нужен процесс? | PrepBro