Taképrogramové vlákno, vlákno procesu, execution threadPokročilý

Definice

Vlákno je samostatná posloupnost vykonávání instrukcí uvnitř procesu, kterou operační systém nebo běhové prostředí plánuje na procesor. Více vláken může sdílet paměť a otevřené zdroje stejného procesu, takže usnadňují souběžnou práci, ale vyžadují synchronizaci kvůli závodům, deadlockům a obtížně reprodukovatelným chybám.

Kategorie: Softwarový vývojAktualizováno

Nezaměňujte: Vlákno může znamenat jednotku souběžného běhu v programu, diskusní konverzaci nebo hardwarové vlákno procesoru; zde jde hlavně o programové vlákno.

Co vlákno sdílí s procesem

Vlákno patří do procesu. Proces drží adresní prostor, otevřené soubory, síťová spojení a další prostředky. Jednotlivá vlákna ve stejném procesu typicky sdílejí haldu a globální data, ale každé vlákno má vlastní zásobník, sadu registrů a místo v programu, kde právě pokračuje.

Plánovač operačního systému rozhoduje, kdy které vlákno dostane čas na procesoru. Na jednom jádře se vlákna střídají tak rychle, že program působí souběžně. Na více jádrech mohou některá vlákna běžet skutečně paralelně. Běhové prostředí jazyka k tomu může přidávat vlastní pravidla, například správu vláken v JVM, .NET runtime nebo omezení GIL v CPythonu.

Proč sdílená paměť komplikuje kód

Sdílená paměť je hlavní důvod, proč jsou vlákna rychlá i nebezpečná. Přístup k jedné proměnné z více vláken může skončit závodem: výsledek závisí na pořadí kroků, které programátor přímo neřídí. Typickým řešením je zámek, mutex, semafor, atomická operace, fronta zpráv nebo neměnná datová struktura.

Synchronizace zároveň něco stojí. Špatně zvolený zámek může zmenšit paralelismus, zavést čekání nebo způsobit deadlock, kdy dvě vlákna navzájem drží prostředky, které potřebuje druhé. Testování takových chyb bývá obtížné, protože problém často zmizí po přidání logování nebo při spuštění na jiném stroji.

Dva praktické scénáře s vláknem

Server zapisuje auditní log mimo hlavní požadavek

Webová aplikace přijme objednávku a potřebuje rychle odpovědět zákazníkovi. Zápis auditního záznamu do pomalejšího úložiště může běžet ve worker vlákně, aby hlavní obsluha požadavku nečekala na disk nebo síť. Výsledek je kratší latence odpovědi, ale aplikace musí ošetřit pád workeru a zaplnění fronty.

import threading

def uloz_audit(objednavka_id):
    print(f"ukládám audit pro {objednavka_id}")

threading.Thread(target=uloz_audit, args=(42,), daemon=True).start()

Mobilní aplikace přesune výpočet mimo UI thread

Mobilní aplikace načítá a zmenšuje velkou fotografii. Výpočet v hlavním UI vlákně by zablokoval kreslení obrazovky a uživatel by viděl zaseknuté rozhraní. Worker vlákno připraví náhled na pozadí a hotový výsledek předá zpět mechanismem, který smí bezpečně měnit uživatelské rozhraní.

Kde se vlákno liší podle prostředí

Vlákno nemusí vždy znamenat totéž na všech úrovních. Nativní vlákno je objekt operačního systému. Vlákno v jazyce může být mapované na nativní vlákno, nebo může jít o lehčí abstrakci spravovanou runtime. Korutina obvykle není totéž co vlákno, protože se přepíná spolupracujícím způsobem a často běží nad menším počtem skutečných vláken.

Hardwarové vlákno je další význam: procesor s technikou simultánního multithreadingu nabízí více logických běhových kontextů na jednom fyzickém jádře. Programátor aplikací však obvykle řeší hlavně programová vlákna, jejich synchronizaci a dopad na odezvu nebo propustnost systému.

Příklady z praxe

  1. Auditní log mimo hlavní požadavek

    Webová aplikace přijme objednávku a nechce zdržovat zákazníka zápisem auditního záznamu do pomalejšího úložiště. Worker vlákno provede zápis na pozadí, hlavní obsluha požadavku vrátí odpověď dříve. Aplikace ale musí ošetřit pád workeru a zaplnění fronty úloh.

    import threading
    
    def uloz_audit(objednavka_id):
        print(f"ukládám audit pro {objednavka_id}")
    
    threading.Thread(target=uloz_audit, args=(42,), daemon=True).start()
  2. Výpočet mimo UI thread

    Mobilní aplikace načítá a zmenšuje velkou fotografii. Výpočet v hlavním UI vlákně by zablokoval kreslení obrazovky a uživatel by viděl zaseknuté rozhraní. Worker vlákno připraví náhled na pozadí a hotový výsledek předá zpět bezpečným mechanismem pro úpravu UI.

Časté omyly

MýtusVlákna vždycky zrychlí program.
Ve skutečnostiVlákna zrychlí jen úlohy, které lze účinně rozdělit nebo které často čekají na I/O. U sdílených dat, častého zamykání nebo omezení runtime může být více vláken dokonce pomalejších.
MýtusKdyž dám všude mutex, bude kód bezpečný.
Ve skutečnostiMutex může zabránit některým závodům, ale nevylučuje deadlock, hladovění ani špatně navržené pořadí operací. Příliš hrubé zamykání navíc často odstraní výhodu paralelismu.

Časté dotazy

Proč vlákno někdy nezrychlí výpočet?
Vlákno někdy nezrychlí výpočet, protože výkon může omezovat jedno jádro, čekání na zámek, přístup do paměti nebo běhové prostředí jazyka. CPython má například GIL, který omezuje paralelní vykonávání běžného Python bytecodu v jednom procesu. Vlákna přesto často pomáhají u I/O úloh, kde program čeká na síť, disk nebo databázi.
Co znamená, že je kód thread-safe?
Thread-safe kód je kód, který se chová správně i při volání z více vláken současně. Thread-safe implementace chrání sdílený stav zámky, používá atomické operace, pracuje s neměnnými hodnotami nebo sdílí data přes fronty. Označení neznamená automaticky vysoký výkon, protože bezpečnost často přidává čekání nebo kopírování dat.
Kolik vláken má aplikace spouštět?
Počet vláken má vycházet z typu práce, omezení runtime a kapacity stroje. Výpočetně náročné úlohy obvykle nemají mít výrazně více běžících vláken než dostupných jader, jinak roste režie přepínání. I/O aplikace mohou snést více vláken, protože mnoho z nich čeká. Praktický limit se ověřuje měřením latence, propustnosti a spotřeby paměti.
Proč vlákna způsobují deadlock?
Deadlock vzniká, když vlákna čekají na prostředky v pořadí, které se navzájem zablokuje. Vlákno A například drží zámek databázové cache a čeká na zámek konfigurace, zatímco vlákno B drží zámek konfigurace a čeká na cache. Deadlock se omezuje pevným pořadím zamykání, časovými limity, menším sdílením stavu a jednodušší strukturou kritických sekcí.

Zdroje

  1. threading — Thread-based parallelism(otevře se v novém okně)Python Software Foundation
  2. Managed threading(otevře se v novém okně)Microsoft
  3. Lesson: Concurrency(otevře se v novém okně)Oracle
  4. Thread (computing)(otevře se v novém okně)Wikipedia

Související pojmy

Potřebujete to vyřešit v praxi?

Poradíme, jak na to ve vašem projektu

Vysvětlit pojem je jedna věc, navrhnout kolem něj funkční řešení druhá. Ozvěte se a probereme, co dává smysl u vás.