0Pricing
Python Academy · Lekcja

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.

Wszystkie lekcje w tym kursie

  1. Wątki i GIL
  2. ThreadPoolExecutor
  3. Podstawy multiprocessing
  4. Bezpieczne współdzielenie danych
← Powrót do Python Academy