Kapitel 11
Ein Vorgeschmack auf Async
Warum die meisten WebSocket-Server asynchron sind
Die meisten async def geschrieben. Deine Anzeigetafel ist es absichtlich nicht: Threads haben es jedem früheren Kapitel erlaubt, einer Verbindung nach der anderen zu folgen, mit der Art von asyncio lesen und ausführen, einen Handler als asyncio richtig zu lernen braucht einen eigenen Kurs: Async Python, der nur Python in der Praxis voraussetzt.
Diese Lektion schreibt keinen Code. Sie fragt, was dein Server aufwendet, während seine Zuschauer warten, und was der andere Stil im Gegenzug verlangt.
Was dein Server aufwendet
Seit Kapitel 7 läuft deine Anzeigetafel auf dem synchronen Server der Bibliothek aus Kapitel 6, der jeder Verbindung einen eigenen Thread gibt. Der Handler läuft in diesem Thread vom
Ein Lauf auf einem lokalen Computer, noch nicht auf der Seite, hat die Threads in einem Serverprozess gezählt. Ohne verbundenen Zuschauer lief der synchrone Server mit 2 Threads: dem Hauptthread und dem, der serve_forever ausführt. Mit 20 untätigen Zuschauern, verbunden aus einem anderen Prozess, waren es 62. Das sind 60 mehr für 20 Zuschauer, drei pro Zuschauer: der Thread, in dem dein Handler läuft, einer, mit dem die Bibliothek die Verbindung liest, und einer für ihr
Deine synchrone Anzeigetafel hat 20 Zuschauer, die alle auf die nächste Wertung warten. Was tut jeder ihrer Handler-Threads?
Ein Zuschauer wartet meistens
Wie viel dieser Zeit ist Arbeit? Nimm einen zweistündigen Quizabend mit 40 Wertungen und nimm an, dass das Senden eines Snapshots an einen Zuschauer etwa eine Millisekunde dauert. Dieser Block macht die Rechnung für einen Zuschauer:
Er gibt busy 0.04 s of 7200 s: 0.0006 % aus. Die Millisekunde ist eine grobe Schätzung, und das Zehnfache würde den Zuschauer immer noch fast den ganzen Abend untätig lassen. Warten ist der normale Zustand eines Zuschauers, wie Kapitel 7 herausfand, als es Zuschauer zum ersten Mal zwischen Wertungen verbunden hielt. Ein Thread pro Zuschauer wird während aller 7200 Sekunden bezahlt, während sich die Arbeit auf weniger als eine Zehntelsekunde summiert.
Warum ist es wichtig, dass ein Zuschauer während deutlich weniger als einem Prozent eines Quiz beschäftigt ist?
Eine Schleife, viele Wartevorgänge
Die andere Form hast du schon gesehen. In Networks with Python hat Kapitel 9 viele Clients aus einem Thread mit selectors bedient: Ein Aufruf, select, wartete, bis irgendein
Eine async def, und Lektion 2 zeigt, wie. Pythons Standard-Event-Loop lebt im asyncio, und die Bibliothek websockets hat einen darauf gebauten Server, websockets.asyncio.
Derselbe lokale Lauf hat auch die Threads dieses Servers gezählt: 1 mit 20 untätigen Zuschauern und 1 ohne. Das Bild stellt die beiden Formen für zwanzig Zuschauer übereinander. Zähle die Threads in jeder und finde den einen Zuschauer, der überhaupt etwas tut.

In der oberen Hälfte hat jeder der zwanzig Zuschauer drei Threads (den seines Handlers, einen Leser und ein Keepalive), dazu die zwei des Servers, und fast alle warten: 2 + 3 x 20 = 62 Threads. In der unteren Hälfte sind dieselben zwanzig Zuschauer geparkt, und ein Thread führt den Zuschauer aus, der gerade weitermachen kann, hier Zuschauer 3, bevor er zur Loop zurückkehrt. Das ist insgesamt 1 Thread.
Der Preis
Die Loop hat einen Thread, also führt sie einen Handler auf einmal aus. Das funktioniert nur, wenn jeder Handler die Kontrolle an die Loop zurückgibt, sobald er warten muss. Ein Handler, der auf die alte Art wartet, mit einem blockierenden Aufruf wie time.sleep oder dem Event.wait der Outbox, hält den einzigen Thread, und jeder andere Zuschauer wartet mit ihm, bis dieser Aufruf zurückkehrt. Lektion 3 zeigt, wie das passiert, mit einer Zählung.
Keiner der beiden Stile ist also einfach besser. Für die fünf Clients, die dieser Kurs gleichzeitig bedient hat, kosten Threads wenig und lassen dich über eine Verbindung nach der anderen nachdenken. Ein Dienst mit Tausenden von Zuschauern, die meistens warten, ist der übliche Grund, auf eine Loop umzusteigen, weil so viele Threads weit mehr kosten würden als die Arbeit, die sie leisten. Das ist das gängige
Welche Situation ist der stärkste Grund, die Anzeigetafel auf eine Event-Loop umzustellen?
In der nächsten Lektion schreibst du deine ersten Coroutinen und führst sie mit asyncio.run auf dem Server aus.