7.1. Threading Aboutï
ZaletÄ wÄ tków jest to, że majÄ wspóÅdzielony stan
Jeden wÄ tek może zapisaÄ kod do pamiÄci a drugi odczytaÄ bez narzutu komunikacyjnego
WadÄ jest również wspóÅdzielony stan i race condition
IdeÄ wÄ tków jest tani dostÄp do wspóÅdzielonej pamiÄci, tylko trzeba wszÄdzie wstawiaÄ locki
Run very fast, but hard to get correct
It's insanely difficult to create large multi-threaded programs with multiple locks
Even if you lock resource, there is no protection if other parts of the system do not even try to acquire the lock
Threads switch preemptively
Preemptively means that the thread manager decides to switch tasks for you (you don't have to explicitly say to do so). Programmer has to do very little.
This is convenient because you don't need to add explicit code to cause a task switch
The cost of this convenience is that you have to assume a switch can happen at any time
Accordingly, critical sections have to be a guarded with locks
The limit on threads is total CPU power minus the cost of tasks switches and synchronization overhead
Why Should Async Get All The Love Advanced Control Flow With Threads [6]
7.1.1. Frequently Asked Questionsï
Co to jest wÄ tek?
Ile czasu trwa tworzenie wÄ tków?
Kto zarzÄ dza wÄ tkami?
Ile może byÄ równolegÅych wÄ tków?
Ile wÄ tków może byÄ w ramach jednego procesu?
Jak komunikowaÄ siÄ miÄdzy wÄ tkami?
Czy wspóÅdzielenie pamiÄci przez wÄ tki jest dobre czy zÅe?
Figure 7.8. Green: actual data transfer; blue: waiting; orange: domain name resolution, TLS handshake, etc. Source: Langa, Å. import asyncio: Learn Python's AsyncIO [3]ï
Every real operating system thread allocates full sized callstack. It's overhead. So you cannot run hundreds of threads without without sacrificing resources [1].
7.1.2. Daemonï
Some threads do background tasks, like sending keepalive packets, or performing periodic garbage collection, or whatever. These are only useful when the main program is running, and it's okay to kill them off once the other, non-daemon, threads have exited.
Without daemon threads, you'd have to keep track of them, and tell them to exit, before your program can completely quit. By setting them as daemon threads, you can let them run and forget about them, and when your program quits, any daemon threads are killed automatically.
7.1.3. GILï
Global Interpreter Lock
CPython has a lock for its internal shared global state
One lock instead of hundreds smaller
The unfortunate effect of GIL is that no more than one thread can run at a time
For I/O bound applications, GIL doesn't present much of an issue
For CPU bound applications, using threads makes the application speed worse
Accordingly, that drives us to multiprocessing to gain more CPU cycles
Larry Hastings, Gilectomy project - removed GIL, but Python slowed down
Source: [1]
7.1.4. Thread-safetyï
Thread-safe code is code that will work even if many Threads are executing it simultaneously.
Thread-safe code is code that will work even if many Threads are executing it simultaneously. Writing it is a black art. It is extremely difficult to debug since you can't reproduce all possible interactions between Threads. You have to do it by logic. In a computer, something that happens only one in a billion times must be dealt with because on average it will happen once a second. To write code that will run stably for weeks takes extreme paranoia [4].
A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code [5].