Nové vlastnosti Pythonu 3.14 v praxi: rychlost a paměťové nároky aplikací využívajících více souběžných úloh

6. 11. 2025
Doba čtení: 29 minut

Sdílet

Python 3.14
Autor: Python
Už jsme si ukázali realizaci souběžných i paralelních úloh v Pythonu 3.14: multiprocesing, multithreading, asynchronní volání a samostatné interpretry. Dnes tato řešení porovnáme z pohledu rychlosti a spotřeby paměti.

Obsah

1. Nové vlastnosti Pythonu 3.14 v praxi: rychlost a paměťové nároky aplikací využívajících více souběžných úloh

2. Základní podoba benchmarků

3. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více vláknech

4. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více procesech

5. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více interpretrech

6. Benchmark zjišťující vlastnosti výpočtů realizovaných asynchronními úlohami

7. Výsledky benchmarků

8. Doba vykonání 100 krátkodobých úloh při nastavení úrovně souběžnosti na 100

9. Doba vykonání 100 déletrvajících úloh při nastavení úrovně souběžnosti na 10

10. Doba vykonání 1000 krátkodobých úloh při nastavení úrovně souběžnosti na 100

11. Doba vykonání 1000 déletrvajících úloh při nastavení úrovně souběžnosti na 100

12. Paměťové nároky všech čtyř variant benchmarků

13. Změřené výsledky: paměťové nároky benchmarků

14. Benchmarky provádějící náročnější výpočty bez I/O operací

15. Zdrojové kódy všech čtyř upravených benchmarků

16. Změřené výsledky

17. Shrnutí

18. Odkazy na články s problematikou souběžnosti a paralelnosti v Pythonu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Nové vlastnosti Pythonu 3.14 v praxi: rychlost a paměťové nároky aplikací využívajících více více souběžných úloh

V předchozím článku o Pythonu 3.14 (tedy o nejnovější v současnosti oficiálně dostupné verzi CPythonu) jsme se zaměřili na popis realizace souběžných a v některých případech i paralelních úloh. Připomeňme si ve stručnosti, že pro realizaci takových úloh je možné využít čtyři rozdílné technologie:

  1. Spuštění úloh asynchronně, což například umožní, aby se (z pohledu času) překrývaly například vstupně-výstupní operace atd. Pro tento účel slouží v Pythonu klíčová slova async a await, které byly přidány již do Pythonu 3.5 (a asyncio.run v Pythonu 3.7).
  2. Spuštění úloh v samostatných vláknech. Konkrétní chování a způsob provedení souběžných výpočtů závisí do značné míry na tom, zda je Python 3.14 přeložen s vestavěným GILem či nikoli. Pokud je GIL použit (standardní interpret), budou úlohy GILem synchronizovány při provádění mnoha operací.
  3. Spuštění úloh v samostatných procesech. Zde se již jedná o řešení, které není omezeno GILem, protože procesy řídí samotné jádro operačního systému, ovšem pravděpodobně za možnost paralelizace zaplatíme větší spotřebou paměti a pomalejším spouštěním úloh.
  4. A konečně spuštění úloh v samostatných interpretrech, přičemž každý interpret poběží v samostatném vláknu. Teoreticky by se mělo toto řešení nacházet na pomezí mezi výše zmíněným multithreadingem a multiprocesingem. Toto řešení je dostupné až od Pythonu 3.14.

V dnešním článku se tato řešení pokusíme porovnat z pohledu celkové rychlosti, rychlosti inicializace a spuštění úloh i z hlediska celkové spotřeby operační paměti.

2. Základní podoba benchmarků

Pro porovnání všech čtyř výše zmíněných technologií určených pro spouštění většího množství souběžných či paralelně běžících úloh nejprve použijeme čtyři základní benchmarky, které budou simulovat skutečné výpočty zavoláním funkce time.sleep popř. její asynchronní varianty. Ve všech benchmarcích budou parametry spouštěných úloh předávány s využitím sdílené fronty (queue) a fronta bude použita i pro ukončení činnosti jednotlivých workerů. Pokaždé je sice fronta realizována jinou technologií, ovšem z pohledu programátora je její chování podobné.

Všechny čtyři benchmarky jsem se snažil vytvořit takovým způsobem, aby se i přes odlišnou technologii spouštění úloh jejich zápis do značné míry podobal. Řízení benchmarků se provádí změnou čtyř globálních proměnných:

# počet souběžně spuštěných vláken, procesů, asychronních úloh nebo interpretrů
CONCURRENCY_LEVEL = 100
 
# celkový počet úloh, které je nutné vypočítat
TASKS = 1000
 
# má se na konci benchmarku čekat na stisk klávesy? (například pro zjištění obsazené paměti)
WAIT_FOR_KEY = False
 
# simulace reálné práce – na tuto dobu bude pozastaveno vlákno,
# proces, asynchronní úloha nebo interpret
SLEEP_AMOUNT = 1

3. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více vláknech

První implementace benchmarku je založena na vykonání úloh ve větším množství vláken – jedná se tedy o klasický multithreading. Vlákna jsou nejdříve vytvořena a poté je v rámci každého z nich spuštěna funkce worker. Parametry úloh jsou předávány přes frontu a předáním příkazu/parametru „quit“ je worker ukončen:

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových vláknech
# - komunikace mezi vlákny s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
 
from queue import Queue
from threading import Thread
import time
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných vláknech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Thread '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Thread '{name}' is about to quit")
            return
        if SLEEP_AMOUNT > 0:
            time.sleep(SLEEP_AMOUNT)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi vlákny
    q = Queue()
 
    ts = []
    # vytvoření procesů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Thread #{i}"
        ts.append(Thread(target=worker, daemon=True, name=name, args=[name, q]))
 
    # spuštění vláken
    for t in ts:
        t.start()
 
    print("Sending data to other threads")
 
    # komunikace s vlákny přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    if WAIT_FOR_KEY:
        input()
 
    print("Asking other threads to finish")
 
    # příkaz pro ukončení vláken
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    print("Waiting for other threads")
 
    # čekání na zpracování všech zpráv ve frontě
    for t in ts:
        t.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

4. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více procesech

Druhá varianta benchmarku používá namísto většího množství vláken pro spuštění workerů samostatné procesy. V takovém případě je přepínání mezi procesy prováděno operačním systémem a procesy by měly běžet do značné míry nezávisle na sobě (ovšem pochopitelně se provádí synchronizace při komunikaci pomocí fronty). Takto upravený benchmark vypadá následovně:

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových procesech
# - komunikace mezi procesy s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
 
import time
from multiprocessing import Process, Queue, freeze_support
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných procesech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Process '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Process '{name}' is about to quit")
            return
        if SLEEP_AMOUNT > 0:
            time.sleep(SLEEP_AMOUNT)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
    freeze_support()
 
    # vytvoření fronty pro komunikaci mezi procesy
    q = Queue()
 
    ps = []
    # vytvoření procesů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Process #{i}"
        ps.append(Process(target=worker, args=(name, q)))
 
    # spuštění procesů
    for p in ps:
        p.start()
 
    print("Sending data to other processes")
 
    # komunikace s procesy přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    if WAIT_FOR_KEY:
        input()
 
    print("Asking other processes to finish")
 
    # příkaz pro ukončení procesů
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    print("Waiting for other processes")
 
    # čekání na ukončení procesů
    for p in ps:
        p.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

5. Benchmark zjišťující vlastnosti výpočtů realizovaných ve více interpretrech

Třetí varianta benchmarku bude funkční pouze v Pythonu 3.14. Úlohy jsou spouštěny v rámci samostatných interpretů, přičemž každý interpret běží v samostatném vlákně. A pro komunikaci mezi workery se pochopitelně opět používá fronta (která ovšem interně vypadá odlišně, než fronty z předchozích dvou benchmarků):

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových interpretrech
# - komunikace mezi interpretry s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
 
import time
from concurrent import interpreters
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných interpretrech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Interpreter '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Interpreter '{name}' is about to quit")
            return
        if SLEEP_AMOUNT > 0:
            time.sleep(SLEEP_AMOUNT)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi interpretry
    q = interpreters.create_queue()
 
    ins = []
    # vytvoření interpretrů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Interpreter #{i}"
        ins.append(interpreters.create().call_in_thread(worker, name, q))
 
    print("Sending data to other interpreters")
 
    # komunikace s interpretry přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    print("Asking other interpreters to finish")
 
    # příkaz pro ukončení procesů
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    if WAIT_FOR_KEY:
        input()
 
    print("Waiting for other interpreters")
 
    # čekání na ukončení interpretrů
    for i in ins:
        i.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

6. Benchmark zjišťující vlastnosti výpočtů realizovaných asynchronními úlohami

Poslední benchmark je naprogramován odlišným způsobem, protože v něm využíváme workery spouštěné v asynchronním kódu. Je zde tedy nutné používat klíčová slova async a await a i hlavní program je realizován asynchronní funkcí. I „čekání“ na dokončení úlohy je realizováno asynchronní operací sleep (to ovšem není férové, proto si ještě ukážeme nepatrně komplikovanější benchmarky):

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh asynchronně
# - komunikace mezi procesy s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
from asyncio import Queue, sleep, run, gather, create_task
import time
 
 
async def worker(name, q):
    """Worker spuštěný několikrát asynchronně."""
    while not q.empty():
        # čtení příkazů z fronty
        cmd = await q.get()
        print(f"Task '{name}' received command '{cmd}'")
        await sleep(SLEEP_AMOUNT)
 
 
async def main():
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi úlohami
    queue = Queue()
 
    print("Sending data to async tasks")
 
    # komunikace s úlohami přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        await queue.put("command {}".format(i))
 
    print("Waiting for all tasks")
 
    aws = [create_task(worker(f"Task #{i}", queue)) for i in range(CONCURRENCY_LEVEL)]
    await gather(*aws)
 
    if WAIT_FOR_KEY:
        input()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")
 
run(main())

7. Výsledky benchmarků

Podívejme se nyní na výsledky benchmarků pro různé nastavení celkového počtu úloh, které se mají vykonat, počtu souběžně pracujících workerů a navíc i minimální doby trvání úloh. Tím si ověříme způsob chování Pythonu v případě, že workery běží v samostatných procesech, ve vláknech, v samostatných interpretrech či jako asynchronní úlohy. Posléze benchmarky upravíme do takové podoby, aby se namísto pouhého čekání (operace sleep) vykonával skutečný výpočet.

8. Doba vykonání 100 krátkodobých úloh při nastavení úrovně souběžnosti na 100

Nejprve všechny benchmarky nastavíme tak, aby se vykonalo pouze 100 úloh, které navíc trvají co nejkratší dobu. Úroveň souběžnosti/paralelnosti je nastavena taktéž na hodnotu 100, což znamená, že podle benchmarku je:

  1. každá úloha vykonána ve svém vlastním vláknu
  2. každá úloha vykonána ve svém vlastním procesu
  3. každá úloha vykonána ve své vlastní asynchronní funkci
  4. každá úloha vykonána ve svém vlastním interpretu

Tyto benchmarky tedy měří primárně rychlost vytvoření workerů.

Nastavení všech benchmarků:

CONCURRENCY_LEVEL = 100
TASKS = 100
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 0

Výsledky:

Typ souběžnosti Celkový čas vykonání
Async 0,0115
Interpreters 3,9117
Processes 0,1410
Threads 0,0620
Poznámka: to, že asynchronní úlohy byly vykonány nejdříve, není překvapující, protože tato technologie je zcela nenáročná a umožňuje v praxi realizovat i statisíce úloh běžících souběžně. Překvapující ani není to, že multithreading je rychlejší než multiprocesing – vytvoření nového threadu je totiž po technologické stránce jednodušší úloha. Ovšem konstrukce a spuštění 100 interpretrů trvalo skoro 4 sekundy, což tento způsob činí zcela nejpomalejší (a je to dosti překvapivé zejména v porovnání s multiprocesingem).

9. Doba vykonání 100 déletrvajících úloh při nastavení úrovně souběžnosti na 10

V dalším kroku konfiguraci benchmarků změníme. Bude se sice opět provádět celkem sto úloh, ovšem úroveň souběžnosti se zmenší na 10 vláken/procesů/interpe­tů/asychronních funkcí a každá úloha bude trvat přibližně jednu sekundu. Takto nastavené benchmarky tedy měří spíše to, do jaké míry běží úlohy paralelně. Teoretická ideální doba běhu bude rovna 100/10=10 sekund.

Nastavení všech benchmarků:

CONCURRENCY_LEVEL = 10
TASKS = 100
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1

Výsledky:

Typ souběžnosti Celkový čas vykonání
Async 10,0192
Interpreters 10,3868
Processes 10,1612
Threads 10,01469
Poznámka: celkové doby běhu jsou prakticky totožné, což znamená, že Python 3.14 bez GILu dokáže spouštět kód ve vláknech velmi efektivně – minimálně tehdy, pokud vlákna pouze čekají na dokončení time.sleep(). Stále však vidíme, že spuštění deseti interpretrů trvalo přibližně 0,38 sekundy (což do značné míry odpovídá předchozímu benchmarku, který spouštěl desetkrát tolik interpretrů).

10. Doba vykonání 1000 krátkodobých úloh při nastavení úrovně souběžnosti na 100

Nyní se pokusíme počet úloh zvýšit na jeden tisíc, ovšem úroveň souběžnosti (počet vláken/procesů/interpretrů/a­synchronních úloh) bude omezena na 100. Jednotlivé úlohy budou prováděny velmi rychle – prakticky bez čekání. Pouze u benchmarku s asynchronními úlohami se čeká na dokončení operace sleep(0), což umožní přepnutí úloh:

Typ souběžnosti Celkový čas vykonání
Async 0,0122
Interpreters 3,8573
Processes 0,5456
Threads 0,1016
Poznámka: opět zde můžeme vidět především dlouhý čas nutný pro spuštění 100 interpretrů. Ostatní výsledky jsou dle očekávání seřazeny (vzestupně) takto: asynchronní úlohy, vlákna a nakonec procesy.

11. Doba vykonání 1000 déletrvajících úloh při nastavení úrovně souběžnosti na 100

Poslední variantou konfigurace benchmarků bude jejich nastavení takovým způsobem, aby se provedlo tisíc úloh s nastavením úrovně souběžnosti na 100. To znamená, že by každý worker (bude jich připraveno celkem 100) měl provést deset úloh. Každá úloha poběží minimálně jednu sekundu, čímž se simuluje reálná práce (tedy s výjimkou asynchronních úloh, kde čekání vede k přepnutí úlohy):

Výsledky benchmarků:

Typ souběžnosti Celkový čas vykonání
Async 10,03398
Interpreters 13,7186
Processes 10,5159
Threads 10,0677
Poznámka: stále je patrné, že kromě pomalejší konstrukce a spuštění interpretrů jsou všechny benchmarky vykonány prakticky ve stejném čase: přibližně deset sekund pro vykonání deseti úloh v každém workerovi, kteří běží souběžně (a v kontextu tohoto benchmarku i paralelně).

12. Paměťové nároky všech čtyř variant benchmarků

Prozatím jsme změřili, jak dlouho trvá vykonání určitého počtu úloh při použití různých technologií. Zajímavé (a popravdě řečeno i dost neočekávané) je, že spouštění úloh v samostatných interpretrech, což je nová technologie Pythonu 3.14, prozatím vychází nejhůře. Je to způsobeno tím, že nejvíce času se stráví inicializací interpretrů – je zde tedy prostor (a to dosti velký) pro další vylepšování v dalších verzích Pythonu.

Ovšem ještě budeme muset změřit paměťové nároky jednotlivých variant benchmarků, protože v praxi se může jednat taktéž o limitující faktor. Dá se předpokládat, že největší paměťové nároky bude mít řešení s větším množstvím procesů, ovšem zajímavé bude zjištění, jaké paměťové nároky má technologie více interpretrů.

13. Změřené výsledky: paměťové nároky benchmarků

Otázkou je, jakým způsobem se mají paměťové nároky měřit. Můžeme například zjistit alokovanou oblast virtuální paměti nebo RSS (což je hodnota, která je asi nejbližší skutečně využívané paměti). Spotřeba paměti bude vyšší u benchmarků s multiprocesingem, protože každý proces znamená nastartování nového interpretru Pythonu. Úlohy spouštěné ve vláknech běží v rámci jednoho procesu a totéž platí i pro úlohy spouštěné ve vlastních interpretrech – každý interpret běží ve vláknu v rámci jediného procesu.

Výsledky pro benchmark s asynchronními úlohami. Bylo naalokováno 1259MB virtuální paměti, ovšem RSS je jen 23,6 MB. Běží, podle očekávání, jen jediný proces Pythonu:

Sledování běžícího benchmarku

Sledování běžícího benchmarku

Autor: tisnik, podle licence: Rights Managed

Výsledky pro benchmark s úlohami běžícími v samostatných vláknech. RSS (jediného procesu) je kupodivu pouze 14,2 MB. Na screenshotu jsou zeleně zobrazena vlákna, nikoli procesy:

Sledování běžícího benchmarku

Sledování běžícího benchmarku

Autor: tisnik, podle licence: Rights Managed

Výsledky pro benchmark s úlohami běžícími v samostatných procesech. Nyní již vidíme mnoho nových procesů s vlastní alokovanou pamětí (17MB pro každý takový proces) a navíc ještě dva další procesy, které vše koordinují. Spotřeba paměti je v tomto případě mnohem vyšší, než u dalších benchmarků:

Sledování běžícího benchmarku

Sledování běžícího benchmarku

Autor: tisnik, podle licence: Rights Managed

A konečně výsledky benchmarku pro deset interpretrů běžících v samostatných vláknech. Nyní sice běží jen jeden proces, ovšem jeho paměťové nároky jsou 79MB, což je více, než u běžného multithreadingu (zeleně jsou opět zobrazena jednotlivá vlákna):

Sledování běžícího benchmarku

Sledování běžícího benchmarku

Autor: tisnik, podle licence: Rights Managed
Typ souběžnosti Celková RSS
Async 23,6 MB
Interpreters 79,0 MB
Processes 204 MB (přibližný výpočet)
Threads 14,2 MB

V tomto ohledu tedy může být použití více interpretrů výhodnější, než klasický multiprocesing.

14. Benchmarky provádějící náročnější výpočty bez I/O operací

Nyní naše čtyři benchmarky nepatrně upravíme, a to takovým způsobem, aby se v nich prováděly nějaké intenzivnější výpočty. Přitom zajistíme, aby se NEpoužívaly vstupně-výstupní operace ani operace sleep, která sice z pohledu jediné úlohy skutečně simuluje práci, ovšem například v případě asynchronních úloh umožní přepínání bez vykonání skutečné činnosti. Výpočtem, které budou benchmarky provádět, je realizace algoritmu pro bublinkové řazení. Tento algoritmus je implementačně jednoduchý, s velkou pravděpodobností nevyužívá SIMD operace (takže procesor nebude zpomalován – viz Intel :-) a skutečně vytíží procesorové jádro nebo jádra:

def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]

15. Zdrojové kódy všech čtyř upravených benchmarků

Bubble sort: asynchronní verze

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh asynchronně
# - komunikace mezi procesy s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
 
 
import random
from asyncio import Queue, sleep, run, gather, create_task
import time
 
 
def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
 
 
async def worker(name, q):
    """Worker spuštěný několikrát asynchronně."""
    while not q.empty():
        # čtení příkazů z fronty
        cmd = await q.get()
        print(f"Task '{name}' received command '{cmd}'")
        bubble_sort(1000)
 
 
async def main():
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi úlohami
    queue = Queue()
 
    print("Sending data to async tasks")
 
    # komunikace s úlohami přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        await queue.put("command {}".format(i))
 
    print("Waiting for all tasks")
 
    aws = [create_task(worker(f"Task #{i}", queue)) for i in range(CONCURRENCY_LEVEL)]
    await gather(*aws)
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")
 
run(main())

Bubble sort: verze s více interpretry běžícími v samostatných vláknech

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových interpretrech
# - komunikace mezi interpretry s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
 
 
import random
import time
from concurrent import interpreters
 
 
def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných interpretrech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Interpreter '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Interpreter '{name}' is about to quit")
            return
        bubble_sort(1000)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi interpretry
    q = interpreters.create_queue()
 
    ins = []
    # vytvoření interpretrů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Interpreter #{i}"
        ins.append(interpreters.create().call_in_thread(worker, name, q))
 
    print("Sending data to other interpreters")
 
    # komunikace s interpretry přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    print("Asking other interpreters to finish")
 
    # příkaz pro ukončení procesů
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    print("Waiting for other interpreters")
 
    # čekání na ukončení interpretrů
    for i in ins:
        i.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

Bubble sort: verze běžící ve více procesech

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových procesech
# - komunikace mezi procesy s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
 
import random
import time
from multiprocessing import Process, Queue, freeze_support
 
 
def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných procesech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Process '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Process '{name}' is about to quit")
            return
        bubble_sort(1000)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
    freeze_support()
 
    # vytvoření fronty pro komunikaci mezi procesy
    q = Queue()
 
    ps = []
    # vytvoření procesů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Process #{i}"
        ps.append(Process(target=worker, args=(name, q)))
 
    # spuštění procesů
    for p in ps:
        p.start()
 
    print("Sending data to other processes")
 
    # komunikace s procesy přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    if WAIT_FOR_KEY:
        input()
 
    print("Asking other processes to finish")
 
    # příkaz pro ukončení procesů
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    print("Waiting for other processes")
 
    # čekání na ukončení procesů
    for p in ps:
        p.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

Bubble sort: verze běžící ve více vláknech

# Multiprocesing a multithreading v Pythonu:
# - spuštění více úloh v nových vláknech
# - komunikace mezi vlákny s využitím fronty
 
CONCURRENCY_LEVEL = 100
TASKS = 1000
WAIT_FOR_KEY = False
SLEEP_AMOUNT = 1
 
 
import random
from queue import Queue
from threading import Thread
import time
 
 
def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
 
 
def worker(name, q):
    """Worker spuštěný několikrát v samostatných vláknech."""
    while True:
        # čtení příkazů z fronty
        cmd = q.get()
        print(f"Thread '{name}' received command '{cmd}'")
        if cmd == "quit":
            print(f"Thread '{name}' is about to quit")
            return
        bubble_sort(1000)
 
 
if __name__ == "__main__":
    t1 = time.time()
 
    print("Starting")
 
    # vytvoření fronty pro komunikaci mezi vlákny
    q = Queue()
 
    ts = []
    # vytvoření procesů
    for i in range(CONCURRENCY_LEVEL):
        name = f"Thread #{i}"
        ts.append(Thread(target=worker, daemon=True, name=name, args=[name, q]))
 
    # spuštění vláken
    for t in ts:
        t.start()
 
    print("Sending data to other threads")
 
    # komunikace s vlákny přes frontu
    for i in range(TASKS):
        print(f"Sending 'command {i}'")
        q.put("command {}".format(i))
 
    if WAIT_FOR_KEY:
        input()
 
    print("Asking other threads to finish")
 
    # příkaz pro ukončení vláken
    for i in range(CONCURRENCY_LEVEL):
        q.put("quit")
 
    print("Waiting for other threads")
 
    # čekání na zpracování všech zpráv ve frontě
    for t in ts:
        t.join()
 
    print("All work done!")
 
    t2 = time.time()
 
    print(f"Elapsed time: {t2-t1}")

16. Změřené výsledky

V tabulce jsou zobrazeny časy běhu benchmarků zaokrouhlených na celé sekundy. První tři benchmarky vykazují při opakovaném spuštění prakticky stejné hodnoty (jsou stabilní), ovšem řešení založené na více vláknech dosti podstatným způsobem kolísá – ovšem jen tehdy, pokud se použije Python 3.14 s vypnutým GILem. Synchronizační mechanismy použité při zakázaném GILu se z tohoto pohledu chovají dosti nedeterministicky. Dále je – což je pochopitelné – čas asynchronní varianty nejpomalejší, neboť se vlastně úlohy provádí sekvenčně. A tento čas je shodný s benchmarkem založeným na použití více vláken, pokud je povolený GIL (který výpočet „serializuje“):

Typ souběžnosti Celkový čas vykonání (bez GILu) Celkový čas vykonání (s GILem)
Async 54 54
Interpreters 13 40
Processes 10 10
Threads 21–45 54

17. Shrnutí

Nová technologie umožňující spouštění výpočtů v izolovaných interpretrech, z nichž každý běží ve vlastním vlákně, má v současné verzi Pythonu tyto vlastnosti, ke kterým je nutné přihlížet:

  • Inicializace a spuštění interpretrů je dosti pomalé, a to i v porovnání se spuštěním více procesů. Tento stav by se však měl postupně zlepšovat.
  • Výkon při zakázaném GILu je stabilní a kupodivu vyšší, než při použití klasického multithreadingu, což je poměrně překvapující zjištění.
  • Paměťové nároky jsou nižší, než při použití více procesů (logicky), ale vyšší, než u klasického multithreadingu.
  • (Asynchronní úlohy jsou vhodné jen pro oblasti s velkým množstvím I/O operací, nikoli pro výpočty).

18. Odkazy na články s problematikou souběžnosti a paralelnosti v Pythonu

Na stránkách Roota jsme se již několikrát setkali s problematikou souběžnosti (concurrency), paralelnosti (parallel run) a asynchronního běhu úloh naprogramovaných v Pythonu. Různé varianty spouštění a řízení více vláken, procesů a asynchronních úloh naleznete v následujících článcích (všechny v článcích uvedené demonstrační příklady by měly být spustitelné i v interpretru Pythonu 3.14 bez povoleného GILu):

  1. Souběžné a paralelně běžící úlohy naprogramované v Pythonu
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu/
  2. Souběžné a paralelně běžící úlohy naprogramované v Pythonu (2)
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-2/
  3. Souběžné a paralelně běžící úlohy naprogramované v Pythonu – Curio a Trio
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-curio-a-trio/
  4. Souběžné a paralelně běžící úlohy naprogramované v Pythonu – knihovna Trio
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-knihovna-trio/
  5. Souběžné a paralelně běžící úlohy naprogramované v Pythonu – knihovna Trio (2)
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-knihovna-trio-2/
  6. Souběžné a paralelně běžící úlohy naprogramované v Pythonu – závěrečné zhodnocení
    https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-zaverecne-zhodnoceni/
  7. Interpret Pythonu bez GILu: vyplatí se odstranění velkého zámku?
    https://www.root.cz/clanky/interpret-pythonu-bez-gilu-vyplati-se-odstraneni-velkeho-zamku/
  8. Nové vlastnosti Pythonu 3.14 v praxi: vliv odstranění GIL a využití více interpretrů
    https://www.root.cz/clanky/nove-vlastnosti-pythonu-3–14-v-praxi-vliv-odstraneni-gil-a-vyuziti-vice-interpretru/
  9. Nové vlastnosti Pythonu 3.14 v praxi: komunikace mezi interpretry
    https://www.root.cz/clanky/nove-vlastnosti-pythonu-3–14-v-praxi-komunikace-mezi-interpretry/

19. Repositář s demonstračními příklady

Všechny demonstrační příklady, které byly popsány v dnešním článku, naleznete na adresách:

# Příklad Stručný popis příkladu Adresa
1 multiple-threads.py benchmark založený na vykonávání úloh v samostatných vláknech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/multiple-threads.py
2 multiple-processes.py benchmark založený na vykonávání úloh v samostatných procesech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/multiple-processes.py
3 multiple-interpreters.py benchmark založený na vykonávání úloh v samostatných interpretech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/multiple-interpreters.py
4 multiple-async.py benchmark založený na vykonávání asynchronních úloh https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/multiple-async.py
       
5 bubble-threads.py benchmark založený na vykonávání úloh v samostatných vláknech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/bubble-threads.py
6 bubble-processes.py benchmark založený na vykonávání úloh v samostatných procesech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/bubble-processes.py
7 bubble-interpreters.py benchmark založený na vykonávání úloh v samostatných interpretech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/bubble-interpreters.py
8 bubble-async.py benchmark založený na vykonávání asynchronních úloh https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ben­chmarks/bubble-async.py

Demonstrační příklady z předchozího článku jsou vypsány v další tabulce:

Školení Hacking

# Příklad Stručný popis příkladu Adresa
1 interpreters/queue-interpreters-1.py poslání zprávy mezi úlohami, které běží v různých interpretrech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-interpreters-1.py
2 interpreters/queue-interpreters-2.py realizace programu pro zpracování úloh v samostatně běžících interpretrech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-interpreters-2.py
3 interpreters/queue-async.py plně asynchronní volání úloh https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-async.py
4 interpreters/queue-multiprocessing.py poslání zprávy mezi úlohami, které běží v různých procesech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-multiprocessing.py
5 interpreters/queue-multithreading-1.py poslání zprávy mezi úlohami, které běží v různých vláknech https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-multithreading-1.py
6 interpreters/queue-multithreading-2.py poslání zprávy mezi úlohami, které běží v různých vláknech, odlišné čekání na dokončení úloh https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-multithreading-2.py
7 interpreters/queue-multithreading-3.py varianta s několika producenty a několika konzumenty https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/queue-multithreading-3.py

Všechny předminule popsané demonstrační příklady jsou vypsány v následující tabulce:

# Příklad Stručný popis příkladu Adresa
1 bubble-sort/bubble_sort_seq.py benchmark provádějící sekvenční volání algoritmu pro bublinkové řazení https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/bubble-sort/bubble_sort_seq.py
2 bubble-sort/bubble_sort_parallel.py benchmark provádějící souběžné volání algoritmu pro bublinkové řazení https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/bubble-sort/bubble_sort_parallel.py
       
3 julia-renderer/julia_seq_anim.py sekvenční výpočet animace Juliových množin https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/julia-renderer/julia_seq_anim.py
4 julia-renderer/julia_parallel_anim.py souběžný popř. paralelní výpočet animace Juliových množin https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/julia-renderer/julia_parallel_anim.py
5 julia-renderer/palette_mandmap.py pomocný soubor s barvovou mapou použitý dvěma předchozími benchmarky https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/julia-renderer/palette_mandmap.py
       
6 interpreters/list-interpreters.py výpis seznamu inicializovaných interpretrů https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/list-interpreters.py
7 interpreters/new-interpreter.py konstrukce nového interpretru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/new-interpreter.py
8 interpreters/exec.py zavolání funkce ve zvoleném interpretru (ve stejném vlákně) https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/exec.py
9 interpreters/call_in_thread.py zavolání funkce ve zvoleném interpretru (v novém vlákně) https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/call_in_thread­.py
10 interpreters/shared-variables.py jsou proměnné sdíleny mezi interpretry? https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/shared-variables.py
11 interpreters/behaviour_exec.py chování dvou interpretrů v čase běhu (metoda exec) https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/behaviour_exec­.py
12 interpreters/behaviour_ca­ll_in_thread.py chování dvou interpretrů v čase běhu (metoda call_in_thread) https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/behaviour_call_in_thre­ad.py
13 interpreters/interpreter_ex­ception1.py chování interpretrů při vyhození nezachycené výjimky https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/interpreter_ex­ception1.py
14 interpreters/interpreter_ex­ception2.py chování interpretrů při vyhození nezachycené výjimky https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/in­terpreters/interpreter_ex­ception2.py

Demonstrační příklady vytvořené pro Python verze 3.14 a popsané v prvním článku najdete v repositáři https://github.com/tisnik/most-popular-python-libs/. Následují odkazy na jednotlivé příklady:

# Příklad Stručný popis Adresa
1 argparse_test.py skript s definicí přepínačů použitelných na příkazovém řádku https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/ar­gparse_test.py
       
2 syntax_error1.py skript obsahující syntaktické chyby: chybějící či naopak přebývající písmeno v klíčovém slovu nebo identifikátoru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/syn­tax_error1.py
2 syntax_error2.py skript obsahující syntaktické chyby: chybějící či naopak přebývající písmeno v klíčovém slovu nebo identifikátoru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/syn­tax_error2.py
3 syntax_error3.py skript obsahující syntaktické chyby: chybějící či naopak přebývající písmeno v klíčovém slovu nebo identifikátoru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/syn­tax_error3.py
4 syntax_error4.py skript obsahující syntaktické chyby: chybějící či naopak přebývající písmeno v klíčovém slovu nebo identifikátoru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/syn­tax_error4.py
5 syntax_error5.py skript obsahující syntaktické chyby: chybějící či naopak přebývající písmeno v klíčovém slovu nebo identifikátoru https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/syn­tax_error5.py
       
6 primes.py realizace výpočtu prvočísel https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/primes.py
7 test_primes.py jednotkové testy pro modul primes.py https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/tes­t_primes.py
       
8 pep-758-motivation-1.py zachycení většího množství výjimek v bloku except – motivační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-758-motivation-1.py
9 pep-758-motivation-2.py zachycení většího množství výjimek v bloku except – motivační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-758-motivation-2.py
10 pep-758-usage.py nový způsob zachycení výjimek definovaný v PEP-758 https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-758-usage.py
11 pep-758-usage-as.py klauzule as a nový způsob zachycení výjimek definovaný v PEP-758 https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-758-usage-as.py
       
12 pep-765-motivation-1.py detekce opuštění bloku finally, první demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-765-motivation-1.py
13 pep-765-motivation-2.py detekce opuštění bloku finally, druhý demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-765-motivation-2.py
14 pep-765-motivation-3.py detekce opuštění bloku finally, třetí demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-765-motivation-3.py
15 pep-765-motivation-4.py detekce opuštění bloku finally, čtvrtý demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/pep-765-motivation-4.py
       
16 f-string-1.py rozdíl mezi f-řetězci a t-řetězci, první demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/f-string-1.py
17 t-string-1.py rozdíl mezi f-řetězci a t-řetězci, první demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/t-string-1.py
18 f-string-2.py rozdíl mezi f-řetězci a t-řetězci, druhý demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/f-string-2.py
19 t-string-2.py rozdíl mezi f-řetězci a t-řetězci, druhý demonstrační příklad https://github.com/tisnik/most-popular-python-libs/blob/master/python3.14/t-string-2.py

20. Odkazy na Internetu

  1. Python 3.14.0
    https://test.python.org/dow­nloads/release/python-3140/
  2. PEP 765 – Disallow return/break/continue that exit a finally block
    https://peps.python.org/pep-0765/
  3. PEP 758 – Allow except and except* expressions without parentheses
    https://peps.python.org/pep-0758/
  4. What’s new in Python 3.14 (official)
    https://docs.python.org/3/what­snew/3.14.html
  5. What’s New In Python 3.13 (official)
    https://docs.python.org/3/what­snew/3.13.html
  6. What’s New In Python 3.12 (official)
    https://docs.python.org/3/what­snew/3.12.html
  7. What’s New In Python 3.11 (official)
    https://docs.python.org/3/what­snew/3.11.html
  8. What’s New In Python 3.12
    https://dev.to/mahiuddindev/python-312–4n43
  9. PEP 698 – Override Decorator for Static Typing
    https://peps.python.org/pep-0698/
  10. PEP 484 – Type Hints
    https://www.python.org/dev/peps/pep-0484/
  11. What’s New In Python 3.5
    https://docs.python.org/3­.5/whatsnew/3.5.html
  12. 26.1. typing — Support for type hints
    https://docs.python.org/3­.5/library/typing.html#mo­dule-typing
  13. Type Hints – Guido van Rossum – PyCon 2015 (youtube)
    https://www.youtube.com/wat­ch?v=2wDvzy6Hgxg
  14. Python 3.5 is on its way
    https://lwn.net/Articles/650904/
  15. Type hints
    https://lwn.net/Articles/640359/
  16. Stránka projektu PDM
    https://pdm.fming.dev/latest/
  17. PDF na GitHubu
    https://github.com/pdm-project/pdm
  18. PEP 582 – Python local packages directory
    https://peps.python.org/pep-0582/
  19. PDM na PyPi
    https://pypi.org/project/pdm/
  20. Which Python package manager should you use?
    https://towardsdatascience.com/which-python-package-manager-should-you-use-d0fd0789a250
  21. How to Use PDM to Manage Python Dependencies without a Virtual Environment
    https://www.youtube.com/wat­ch?v=qOIWNSTYfcc
  22. What are the best Python package managers?
    https://www.slant.co/topics/2666/~best-python-package-managers
  23. PEP 621 – Storing project metadata in pyproject.toml
    https://peps.python.org/pep-0621/
  24. Pick a Python Lockfile and Improve Security
    https://blog.phylum.io/pick-a-python-lockfile-and-improve-security/
  25. PyPA specifications
    https://packaging.python.or­g/en/latest/specification­s/
  26. Creation of virtual environments
    https://docs.python.org/3/li­brary/venv.html
  27. How to Use virtualenv in Python
    https://learnpython.com/blog/how-to-use-virtualenv-python/
  28. Python Virtual Environments: A Primer
    https://realpython.com/python-virtual-environments-a-primer/
  29. virtualenv Cheatsheet
    https://aaronlelevier.git­hub.io/virtualenv-cheatsheet/
  30. Installing Python Modules
    https://docs.python.org/3/in­stalling/index.html
  31. Python: The Documentary | An origin story
    https://www.youtube.com/wat­ch?v=GfH4QL4VqJ0
  32. History of Python
    https://en.wikipedia.org/wi­ki/History_of_Python
  33. History of Python
    https://www.geeksforgeeks­.org/python/history-of-python/
  34. IPython: jedno z nejpropracovanějších interaktivních prostředí pro práci s Pythonem
    https://www.root.cz/clanky/ipython-jedno-z-nejpropracova-nejsich-interaktivnich-prostredi-pro-praci-s-pythonem/
  35. Další kulaté výročí v IT: dvacet let existence Pythonu 2
    https://www.root.cz/clanky/dalsi-kulate-vyroci-v-it-dvacet-let-existence-pythonu-2/
  36. PEP 684 – A Per-Interpreter GIL
    https://peps.python.org/pep-0684/
  37. What Is the Python Global Interpreter Lock (GIL)?
    https://realpython.com/python-gil/
  38. PEP 703 – Making the Global Interpreter Lock Optional in CPython
    https://peps.python.org/pep-0703/
  39. GlobalInterpreterLock
    https://wiki.python.org/mo­in/GlobalInterpreterLock
  40. What is the Python Global Interpreter Lock (GIL)
    https://www.geeksforgeeks.org/what-is-the-python-global-interpreter-lock-gil/
  41. Let's remove the Global Interpreter Lock
    https://www.pypy.org/posts/2017/08/lets-remove-global-interpreter-lock-748023554216649595.html
  42. Global interpreter lock
    https://en.wikipedia.org/wi­ki/Global_interpreter_lock
  43. Rychlost CPythonu 3.11 a 3.12 v porovnání s JIT a AOT překladači
    https://www.root.cz/clanky/rychlost-cpythonu-3–11-a-3–12-v-porovnani-s-jit-a-aot-prekladaci-pythonu/
  44. Dokumentace Pythonu: balíček queue
    https://docs.python.org/3/li­brary/queue.html
  45. Dokumentace Pythonu: balíček threading
    https://docs.python.org/3/li­brary/threading.html?
  46. Dokumentace Pythonu: balíček multiprocessing
    https://docs.python.org/3/li­brary/multiprocessing.html
  47. Dokumentace Pythonu: balíček asyncio
    https://docs.python.org/3/li­brary/asyncio.html
  48. Synchronization Primitives
    https://docs.python.org/3/li­brary/asyncio-sync.html
  49. Coroutines
    https://docs.python.org/3/li­brary/asyncio-task.html
  50. Queues
    https://docs.python.org/3/li­brary/asyncio-queue.html
  51. python-csp
    https://python-csp.readthedocs.io/en/latest/
  52. TrellisSTM
    http://peak.telecommunity­.com/DevCenter/TrellisSTM
  53. Python Multithreading and Multiprocessing Tutorial
    https://www.toptal.com/pyt­hon/beginners-guide-to-concurrency-and-parallelism-in-python
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.