Wątki i GIL
Poznaj ograniczenia wielowątkowości w Pythonie
Wątki i GIL to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.
Czym jest wątek
Wątek to osobny przepływ wykonywania wewnątrz jednego procesu. Moduł threading języka Python umożliwia współbieżne uruchamianie funkcji w ramach jednego programu.
import threading
def worker():
print('hello from thread')
t = threading.Thread(target=worker)
t.start()
t.join()
print('main done')Uruchamianie wielu wątków
Można uruchomić kilka wątków. Każdy wykonuje swoją funkcję docelową. Metoda join() sprawia, że wątek główny czeka na zakończenie danego wątku.
import threading
def task(name):
print('task', name)
threads = [threading.Thread(target=task, args=(i,)) for i in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
print('all finished')Globalna blokada interpretera
CPython ma globalną blokadę interpretera (GIL): w danym momencie tylko jeden wątek wykonuje kod bajtowy Pythona. Oznacza to, że wątki nie zapewniają rzeczywistego przyspieszenia równoległego w przypadku obliczeń wykonywanych wyłącznie w Pythonie.
import sys
print('Running on:', sys.implementation.name)
print('Only one thread runs Python bytecode at a time due to the GIL')Kiedy wątki nadal pomagają
Wątki świetnie sprawdzają się w zadaniach ograniczonych przez operacje wejścia-wyjścia: żądaniach sieciowych, odczycie z dysku i oczekiwaniu. Gdy jeden wątek czeka, GIL zostaje zwolniona i może działać inny wątek.
import threading, time
def fake_io(name):
time.sleep(0.1)
print('done', name)
start = time.perf_counter()
ts = [threading.Thread(target=fake_io, args=(i,)) for i in range(3)]
for t in ts: t.start()
for t in ts: t.join()
print('elapsed about 0.1s, not 0.3s')Obliczenia ograniczone przez CPU nie przyspieszają
W przypadku intensywnych obliczeń dodanie wątków nie przyspieszy działania, ponieważ GIL wykonuje je szeregowo. Do zadań obciążających CPU należy zamiast tego użyć multiprocessing.
import threading
def burn():
total = 0
for i in range(1000000):
total += i
return total
t = threading.Thread(target=burn)
t.start()
t.join()
print('CPU-bound: threads share one core under the GIL')Wątki daemon
Wątek daemon jest automatycznie kończony, gdy kończy się główny program. Należy używać go do zadań pomocniczych działających w tle, na które nie trzeba czekać.
import threading, time
def background():
time.sleep(0.05)
print('background tick')
t = threading.Thread(target=background, daemon=True)
t.start()
t.join()
print('main exits')Nazywanie i identyfikowanie wątków
Każdy wątek ma nazwę i identyfikator. threading.current_thread() zwraca obiekt aktualnie działającego wątku, co jest przydatne podczas rejestrowania informacji.
import threading
def show():
t = threading.current_thread()
print('running in', t.name)
t = threading.Thread(target=show, name='Worker-1')
t.start()
t.join()
print('main thread:', threading.current_thread().name)Dziedziczenie po klasie Thread
Zamiast przekazywać funkcję docelową można utworzyć podklasę Thread i przesłonić metodę run(). Jest to przydatne, gdy wątek musi przechowywać własny stan.
import threading
class Greeter(threading.Thread):
def __init__(self, name):
super().__init__()
self.who = name
def run(self):
print('hi', self.who)
g = Greeter('Sam')
g.start()
g.join()Zwracanie wyników z wątków
Wartość zwracana przez funkcję docelową jest odrzucana. Aby zebrać wyniki, należy zapisać je we współdzielonej strukturze — później poznasz bezpieczniejsze narzędzia, takie jak kolejki.
import threading
results = {}
def compute(key):
results[key] = key * key
ts = [threading.Thread(target=compute, args=(i,)) for i in range(4)]
for t in ts: t.start()
for t in ts: t.join()
print(results)Zliczanie aktywnych wątków
threading.active_count() informuje, ile wątków jest obecnie aktywnych, wliczając wątek główny.
import threading, time
def wait():
time.sleep(0.05)
ts = [threading.Thread(target=wait) for _ in range(2)]
for t in ts: t.start()
print('active now:', threading.active_count())
for t in ts: t.join()
print('active after join:', threading.active_count())Wybór między wątkami a procesami
Zasada praktyczna: należy używać wątków do współbieżnych zadań ograniczonych przez operacje wejścia-wyjścia oraz procesów do równoległych zadań ograniczonych przez CPU. Powodem jest GIL.
tasks = {'download files': 'threads', 'crunch numbers': 'processes', 'call APIs': 'threads'}
for task, choice in tasks.items():
print(task, '->', choice)Szybkie sprawdzenie
Sprawdź swoją znajomość wątków i GIL.
Podsumowanie
Poznałeś(-aś) wątki i GIL:
- Wątki działają współbieżnie w jednym procesie za pośrednictwem
threading.Thread. - GIL wykonuje kod bajtowy Pythona szeregowo.
- Wątki pomagają w zadaniach ograniczonych przez operacje wejścia-wyjścia, a procesy w zadaniach ograniczonych przez CPU.
- Należy używać
start(),join(), wątków daemon i dziedziczenia po klasie.
Następnie poznasz uporządkowane zarządzanie wątkami za pomocą ThreadPoolExecutor.
Często zadawane pytania
Czy lekcja „Wątki i GIL” jest bezpłatna?
Tak — pełny tekst „Wątki i GIL” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wątki i GIL”?
Poznaj ograniczenia wielowątkowości w Pythonie Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Python Academy?
Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Wątki i GIL”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?
Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.