Przetwarzanie równoległe w Pythonie: realne oszczędności
Python jest jednym z najpopularniejszych języków w web developmentie, automatyzacji i data science. Ale ma swoją piętę achillesową – Global Interpreter Lock (GIL). Dla wielu firm oznacza to, że aplikacje nie wykorzystują w pełni nowoczesnych, wielordzeniowych procesorów. Efekt? Wolniejsze działanie, większe koszty infrastruktury i frustracja użytkowników.
W tym artykule pokażę, jak realnie wdrożyć przetwarzanie równoległe w Pythonie, bez zbędnych komplikacji. Podam konkretne przykłady, gdzie to ma sens, a gdzie lepiej odpuścić.
Dlaczego Python jest wolny przy wielu zadaniach naraz?
GIL to mechanizm, który pozwala na wykonanie tylko jednego wątku na raz. W praktyce oznacza to, że programy wielowątkowe w Pythonie nie przyspieszają na CPU-bound taskach (obliczeniach). Jednak przy zadaniach I/O (np. zapytania do bazy, API, odczyty plików) GIL nie jest problemem, bo wątki czekają na zewnętrzne odpowiedzi.
Dlatego kluczowe jest rozróżnienie dwóch typów zadań:
- CPU-bound: obliczenia, pętle, przetwarzanie danych
- I/O-bound: zapytania sieciowe, operacje na dysku
Dla pierwszych potrzebujemy multiprocessingu, dla drugich – asyncio lub threadingu.
Kiedy multiprocessing ma sens?
Wyobraźmy sobie sklep e-commerce, który codziennie przetwarza logi kliknięć użytkowników. Każdy log to JSON z dziesiątkami pól. Firma używa Pythona do parsowania i agregacji danych. Na jednym rdzeniu proces trwa 30 minut. Dzięki podziałowi na 4 procesy (bo serwer ma 4 rdzenie) czas skraca się do 8 minut. To realna oszczędność czasu i pieniędzy.
Przykład kodu:
from multiprocessing import Pool
import json
def parse_log(file_path):
with open(file_path, 'r') as f:
data = json.load(f)
# przetwarzanie
return processed_data
if __name__ == '__main__':
files = ['log1.json', 'log2.json', ...]
with Pool(4) as p:
results = p.map(parse_log, files)
Proste, a daje ogromny zysk.
Asyncio – król zadań sieciowych
Jeśli Twoja aplikacja musi wykonać 100 zapytań do różnych API (np. pobranie cen z hurtowni), asyncio pozwala zrobić to w sekundę zamiast minuty. W JurskiTech często stosujemy to przy integracjach API – klient dostaje dane w czasie rzeczywistym.
Wada? Kod asynchroniczny wymaga innego myślenia i narzędzi (aiohttp zamiast requests). Ale warto.
Gdzie nie stosować przetwarzania równoległego?
I tu uwaga – nie każde zadanie wymaga paralelizacji. W małych skryptach uruchamianych raz dziennie różnica 2 sekund jest bez znaczenia. Komplikowanie kodu generuje dług techniczny. Pamiętaj: dodanie multiprocessingu wiąże się z większym zużyciem RAM i ryzykiem błędów (np. przy współdzieleniu plików).
Dlatego zawsze mierz, zanim optymalizujesz. Użyj profilera (cProfile) i sprawdź, które fragmenty są faktycznie wąskim gardłem.
Podsumowanie
Przetwarzanie równoległe w Pythonie to narzędzie, które w odpowiednich rękach pozwala zaoszczędzić czas i pieniądze. Klucz to zrozumienie GIL i dobranie właściwej metody do typu zadania. Dla CPU-bound -> multiprocessing, dla I/O-bound -> asyncio lub threading. Nie stosuj na siłę – zmierz, oceń, wdróż.
W JurskiTech pomagamy firmom optymalizować aplikacje Python. Jeśli chcesz przyspieszyć swoje backendy – daj znać.


