Browse Source

Threading, Coroutines

main
Jure Šorn 1 month ago
parent
commit
ce55a2b3c6
3 changed files with 38 additions and 38 deletions
  1. 34
      README.md
  2. 38
      index.html
  3. 4
      parse.js

34
README.md

@ -2258,15 +2258,15 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
### Lock
```python
<lock> = Lock/RLock() # RLock can only be released by acquirer.
<lock>.acquire() # Waits for the lock to be available.
<lock>.release() # Makes the lock available again.
<lock> = Lock/RLock() # RLock can only be released by acquirer thread.
<lock>.acquire() # Blocks (waits) until lock becomes available.
<lock>.release() # It makes the acquired lock available again.
```
#### Or:
```python
with <lock>: # Enters the block by calling acquire() and
... # exits it with release(), even on error.
with <lock>: # Enters the block by calling method acquire().
... # Exits by calling release(), even on error.
```
### Semaphore, Event, Barrier
@ -2278,11 +2278,11 @@ with <lock>: # Enters the block by calling acq
### Queue
```python
<Queue> = queue.Queue(maxsize=0) # A thread-safe first-in-first-out queue.
<Queue>.put(<el>) # Blocks until queue stops being full.
<Queue>.put_nowait(<el>) # Raises queue.Full exception if full.
<el> = <Queue>.get() # Blocks until queue stops being empty.
<el> = <Queue>.get_nowait() # Raises queue.Empty exception if empty.
<Queue> = queue.Queue(maxsize=0) # A first-in-first-out queue. It's thread safe.
<Queue>.put(<obj>) # Call blocks until queue stops being full.
<Queue>.put_nowait(<obj>) # Raises queue.Full exception if queue is full.
<obj> = <Queue>.get() # Call blocks until queue stops being empty.
<obj> = <Queue>.get_nowait() # Raises queue.Empty exception if it's empty.
```
### Thread Pool Executor
@ -2290,12 +2290,12 @@ with <lock>: # Enters the block by calling acq
<Exec> = ThreadPoolExecutor(max_workers=None) # Also `with ThreadPoolExecutor() as <name>: …`.
<iter> = <Exec>.map(<func>, <args_1>, ...) # Multithreaded and non-lazy map(). Keeps order.
<Futr> = <Exec>.submit(<func>, <arg_1>, ...) # Creates a thread and returns its Future obj.
<Exec>.shutdown() # Waits for all submitted threads to finish.
<Exec>.shutdown() # Waits for all threads to finish executing.
```
```python
<bool> = <Future>.done() # Checks if the thread has finished executing.
<obj> = <Future>.result(timeout=None) # Waits for thread to finish and returns result.
<obj> = <Future>.result(timeout=None) # Raises TimeoutError after 'timeout' seconds.
<bool> = <Future>.cancel() # Cancels or returns False if running/finished.
<iter> = as_completed(<coll_of_Futures>) # `next(<iter>)` returns next completed Future.
```
@ -2306,8 +2306,8 @@ with <lock>: # Enters the block by calling acq
Coroutines
----------
* **Coroutines have a lot in common with threads, but unlike threads, they only give up control when they call another coroutine and they don’t use as much memory.**
* **Coroutine definition starts with `'async'` and its call with `'await'`.**
* **Coroutines have a lot in common with threads, but unlike threads, they only give up control when they call another coroutine and they don’t consume as much memory.**
* **Coroutine definition starts with `'async'` and its call with `'await'` keyword.**
* **Use `'asyncio.run(<coroutine>)'` to start the first/main coroutine.**
```python
@ -2316,7 +2316,7 @@ import asyncio as aio
```python
<coro> = <async_function>(<args>) # Creates a coroutine by calling async def function.
<obj> = await <coroutine> # Starts the coroutine and waits for its result.
<obj> = await <coroutine> # Starts the coroutine. Returns its result or None.
<task> = aio.create_task(<coroutine>) # Schedules it for execution. Always keep the task.
<obj> = await <task> # Returns coroutine's result. Also <task>.cancel().
```
@ -2344,7 +2344,7 @@ async def main_coroutine(screen):
moves = asyncio.Queue()
state = {'*': P(0, 0)} | {id_: P(W//2, H//2) for id_ in range(10)}
ai = [random_controller(id_, moves) for id_ in range(10)]
mvc = [human_controller(screen, moves), model(moves, state), view(state, screen)]
mvc = [controller(screen, moves), model(moves, state), view(state, screen)]
tasks = [asyncio.create_task(coro) for coro in ai + mvc]
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
@ -2354,7 +2354,7 @@ async def random_controller(id_, moves):
moves.put_nowait((id_, d))
await asyncio.sleep(random.triangular(0.01, 0.65))
async def human_controller(screen, moves):
async def controller(screen, moves):
while True:
key_mappings = {258: D.s, 259: D.n, 260: D.w, 261: D.e}
if d := key_mappings.get(screen.getch()):

38
index.html

@ -56,7 +56,7 @@
<body>
<header>
<aside>July 31, 2025</aside>
<aside>September 4, 2025</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</header>
@ -1863,13 +1863,13 @@ delattr(&lt;obj&gt;, <span class="hljs-string">'&lt;name&gt;'</span>)
<li><strong>Use <code class="python hljs"><span class="hljs-string">'kwargs=&lt;dict&gt;'</span></code> to pass keyword arguments to the function.</strong></li>
<li><strong>Use <code class="python hljs"><span class="hljs-string">'daemon=True'</span></code>, or the program won't be able to exit while the thread is alive.</strong></li>
</ul>
<div><h3 id="lock">Lock</h3><pre><code class="python language-python hljs">&lt;lock&gt; = Lock/RLock() <span class="hljs-comment"># RLock can only be released by acquirer.</span>
&lt;lock&gt;.acquire() <span class="hljs-comment"># Waits for the lock to be available.</span>
&lt;lock&gt;.release() <span class="hljs-comment"># Makes the lock available again.</span>
<div><h3 id="lock">Lock</h3><pre><code class="python language-python hljs">&lt;lock&gt; = Lock/RLock() <span class="hljs-comment"># RLock can only be released by acquirer thread.</span>
&lt;lock&gt;.acquire() <span class="hljs-comment"># Blocks (waits) until lock becomes available.</span>
&lt;lock&gt;.release() <span class="hljs-comment"># It makes the acquired lock available again.</span>
</code></pre></div>
<div><h4 id="or-1">Or:</h4><pre><code class="python language-python hljs"><span class="hljs-keyword">with</span> &lt;lock&gt;: <span class="hljs-comment"># Enters the block by calling acquire() and</span>
... <span class="hljs-comment"># exits it with release(), even on error.</span>
<div><h4 id="or-1">Or:</h4><pre><code class="python language-python hljs"><span class="hljs-keyword">with</span> &lt;lock&gt;: <span class="hljs-comment"># Enters the block by calling method acquire().</span>
... <span class="hljs-comment"># Exits by calling release(), even on error.</span>
</code></pre></div>
<div><h3 id="semaphoreeventbarrier">Semaphore, Event, Barrier</h3><pre><code class="python language-python hljs">&lt;Semaphore&gt; = Semaphore(value=<span class="hljs-number">1</span>) <span class="hljs-comment"># Lock that can be acquired by 'value' threads.</span>
@ -1877,21 +1877,21 @@ delattr(&lt;obj&gt;, <span class="hljs-string">'&lt;name&gt;'</span>)
&lt;Barrier&gt; = Barrier(n_times) <span class="hljs-comment"># Wait() blocks until it's called n times.</span>
</code></pre></div>
<div><h3 id="queue">Queue</h3><pre><code class="python language-python hljs">&lt;Queue&gt; = queue.Queue(maxsize=<span class="hljs-number">0</span>) <span class="hljs-comment"># A thread-safe first-in-first-out queue.</span>
&lt;Queue&gt;.put(&lt;el&gt;) <span class="hljs-comment"># Blocks until queue stops being full.</span>
&lt;Queue&gt;.put_nowait(&lt;el&gt;) <span class="hljs-comment"># Raises queue.Full exception if full.</span>
&lt;el&gt; = &lt;Queue&gt;.get() <span class="hljs-comment"># Blocks until queue stops being empty.</span>
&lt;el&gt; = &lt;Queue&gt;.get_nowait() <span class="hljs-comment"># Raises queue.Empty exception if empty.</span>
<div><h3 id="queue">Queue</h3><pre><code class="python language-python hljs">&lt;Queue&gt; = queue.Queue(maxsize=<span class="hljs-number">0</span>) <span class="hljs-comment"># A first-in-first-out queue. It's thread safe.</span>
&lt;Queue&gt;.put(&lt;obj&gt;) <span class="hljs-comment"># Call blocks until queue stops being full.</span>
&lt;Queue&gt;.put_nowait(&lt;obj&gt;) <span class="hljs-comment"># Raises queue.Full exception if queue is full.</span>
&lt;obj&gt; = &lt;Queue&gt;.get() <span class="hljs-comment"># Call blocks until queue stops being empty.</span>
&lt;obj&gt; = &lt;Queue&gt;.get_nowait() <span class="hljs-comment"># Raises queue.Empty exception if it's empty.</span>
</code></pre></div>
<div><h3 id="threadpoolexecutor">Thread Pool Executor</h3><pre><code class="python language-python hljs">&lt;Exec&gt; = ThreadPoolExecutor(max_workers=<span class="hljs-keyword">None</span>) <span class="hljs-comment"># Also `with ThreadPoolExecutor() as &lt;name&gt;: …`.</span>
&lt;iter&gt; = &lt;Exec&gt;.map(&lt;func&gt;, &lt;args_1&gt;, ...) <span class="hljs-comment"># Multithreaded and non-lazy map(). Keeps order.</span>
&lt;Futr&gt; = &lt;Exec&gt;.submit(&lt;func&gt;, &lt;arg_1&gt;, ...) <span class="hljs-comment"># Creates a thread and returns its Future obj.</span>
&lt;Exec&gt;.shutdown() <span class="hljs-comment"># Waits for all submitted threads to finish.</span>
&lt;Exec&gt;.shutdown() <span class="hljs-comment"># Waits for all threads to finish executing.</span>
</code></pre></div>
<pre><code class="python language-python hljs">&lt;bool&gt; = &lt;Future&gt;.done() <span class="hljs-comment"># Checks if the thread has finished executing.</span>
&lt;obj&gt; = &lt;Future&gt;.result(timeout=<span class="hljs-keyword">None</span>) <span class="hljs-comment"># Waits for thread to finish and returns result.</span>
&lt;obj&gt; = &lt;Future&gt;.result(timeout=<span class="hljs-keyword">None</span>) <span class="hljs-comment"># Raises TimeoutError after 'timeout' seconds.</span>
&lt;bool&gt; = &lt;Future&gt;.cancel() <span class="hljs-comment"># Cancels or returns False if running/finished.</span>
&lt;iter&gt; = as_completed(&lt;coll_of_Futures&gt;) <span class="hljs-comment"># `next(&lt;iter&gt;)` returns next completed Future.</span>
</code></pre>
@ -1901,15 +1901,15 @@ delattr(&lt;obj&gt;, <span class="hljs-string">'&lt;name&gt;'</span>)
<li><strong>ProcessPoolExecutor provides true parallelism but: everything sent to/from workers must be <a href="#pickle">pickable</a>, queues must be sent using executor's 'initargs' and 'initializer' parameters, and executor should only be reachable via <code class="python hljs"><span class="hljs-string">'if __name__ == "__main__": ...'</span></code>.</strong></li>
</ul>
<div><h2 id="coroutines"><a href="#coroutines" name="coroutines">#</a>Coroutines</h2><ul>
<li><strong>Coroutines have a lot in common with threads, but unlike threads, they only give up control when they call another coroutine and they don’t use as much memory.</strong></li>
<li><strong>Coroutine definition starts with <code class="python hljs"><span class="hljs-string">'async'</span></code> and its call with <code class="python hljs"><span class="hljs-string">'await'</span></code>.</strong></li>
<li><strong>Coroutines have a lot in common with threads, but unlike threads, they only give up control when they call another coroutine and they don’t consume as much memory.</strong></li>
<li><strong>Coroutine definition starts with <code class="python hljs"><span class="hljs-string">'async'</span></code> and its call with <code class="python hljs"><span class="hljs-string">'await'</span></code> keyword.</strong></li>
<li><strong>Use <code class="python hljs"><span class="hljs-string">'asyncio.run(&lt;coroutine&gt;)'</span></code> to start the first/main coroutine.</strong></li>
</ul><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> asyncio <span class="hljs-keyword">as</span> aio
</code></pre></div>
<pre><code class="python language-python hljs">&lt;coro&gt; = &lt;async_function&gt;(&lt;args&gt;) <span class="hljs-comment"># Creates a coroutine by calling async def function.</span>
&lt;obj&gt; = <span class="hljs-keyword">await</span> &lt;coroutine&gt; <span class="hljs-comment"># Starts the coroutine and waits for its result.</span>
&lt;obj&gt; = <span class="hljs-keyword">await</span> &lt;coroutine&gt; <span class="hljs-comment"># Starts the coroutine. Returns its result or None.</span>
&lt;task&gt; = aio.create_task(&lt;coroutine&gt;) <span class="hljs-comment"># Schedules it for execution. Always keep the task.</span>
&lt;obj&gt; = <span class="hljs-keyword">await</span> &lt;task&gt; <span class="hljs-comment"># Returns coroutine's result. Also &lt;task&gt;.cancel().</span>
</code></pre>
@ -1932,7 +1932,7 @@ W, H = <span class="hljs-number">15</span>, <span class="hljs-number">7</span>
moves = asyncio.Queue()
state = {<span class="hljs-string">'*'</span>: P(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)} | {id_: P(W//<span class="hljs-number">2</span>, H//<span class="hljs-number">2</span>) <span class="hljs-keyword">for</span> id_ <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)}
ai = [random_controller(id_, moves) <span class="hljs-keyword">for</span> id_ <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)]
mvc = [human_controller(screen, moves), model(moves, state), view(state, screen)]
mvc = [controller(screen, moves), model(moves, state), view(state, screen)]
tasks = [asyncio.create_task(coro) <span class="hljs-keyword">for</span> coro <span class="hljs-keyword">in</span> ai + mvc]
<span class="hljs-keyword">await</span> asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
@ -1942,7 +1942,7 @@ W, H = <span class="hljs-number">15</span>, <span class="hljs-number">7</span>
moves.put_nowait((id_, d))
<span class="hljs-keyword">await</span> asyncio.sleep(random.triangular(<span class="hljs-number">0.01</span>, <span class="hljs-number">0.65</span>))
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">controller</span><span class="hljs-params">(screen, moves)</span>:</span>
<span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:
key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e}
<span class="hljs-keyword">if</span> d := key_mappings.get(screen.getch()):
@ -2934,7 +2934,7 @@ $ deactivate <span class="hljs-comment"># Deactivates the active
<footer>
<aside>July 31, 2025</aside>
<aside>September 4, 2025</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</footer>

4
parse.js

@ -133,7 +133,7 @@ const COROUTINES =
' moves = asyncio.Queue()\n' +
' state = {<span class="hljs-string">\'*\'</span>: P(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)} | {id_: P(W//<span class="hljs-number">2</span>, H//<span class="hljs-number">2</span>) <span class="hljs-keyword">for</span> id_ <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)}\n' +
' ai = [random_controller(id_, moves) <span class="hljs-keyword">for</span> id_ <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)]\n' +
' mvc = [human_controller(screen, moves), model(moves, state), view(state, screen)]\n' +
' mvc = [controller(screen, moves), model(moves, state), view(state, screen)]\n' +
' tasks = [asyncio.create_task(coro) <span class="hljs-keyword">for</span> coro <span class="hljs-keyword">in</span> ai + mvc]\n' +
' <span class="hljs-keyword">await</span> asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n' +
'\n' +
@ -143,7 +143,7 @@ const COROUTINES =
' moves.put_nowait((id_, d))\n' +
' <span class="hljs-keyword">await</span> asyncio.sleep(random.triangular(<span class="hljs-number">0.01</span>, <span class="hljs-number">0.65</span>))\n' +
'\n' +
'<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span>\n' +
'<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">controller</span><span class="hljs-params">(screen, moves)</span>:</span>\n' +
' <span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:\n' +
' key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e}\n' +
' <span class="hljs-keyword">if</span> d := key_mappings.get(screen.getch()):\n' +

Loading…
Cancel
Save