|
112 | 112 | "source": [ |
113 | 113 | "[Pretty much everything](https://docs.python.org/3/library/contextlib.html) in the `contextlib` module that does not have the word `async` in it is worth learning. `contextlib.closing` turns an object with a `.close()` into a context manager, and `contextlib.ExitStack` lets you nest context managers without eating up massive amounts of whitespace." |
114 | 114 | ] |
115 | | - }, |
116 | | - { |
117 | | - "cell_type": "markdown", |
118 | | - "metadata": {}, |
119 | | - "source": [ |
120 | | - "## Quick note: Async\n", |
121 | | - "\n", |
122 | | - "Everything we've been doing has built on itself, and we seemed to be going somewhere; the pinnacle of this direction was actually not context managers, but `async/await`. All of this feeds into `async/await`, which was formally introduced as a language component in Python 3.6. However, we did skip a necessary step; we didn't talk about generators (iterators can actually \"send\" values in, not just produce them, but there's no specific construct for doing that, like there is for consuming values in a for loop). The main reason we didn't try to reach `async` though is that I've never found a great use for it in scientific programming; it is much more intrusive than normal threading, it doesn't really \"live\" side-by-side with normal synchronous programming all that well (it's better now, though), and the libraries for it are a little young. Feel free to investigate on your own, though! I've also discussed the mechanisms behind it in detail in my blog a few years ago." |
123 | | - ] |
124 | | - }, |
125 | | - { |
126 | | - "cell_type": "markdown", |
127 | | - "metadata": {}, |
128 | | - "source": [ |
129 | | - "Let's whet your appetite with a quick example, though:" |
130 | | - ] |
131 | | - }, |
132 | | - { |
133 | | - "cell_type": "code", |
134 | | - "execution_count": null, |
135 | | - "metadata": {}, |
136 | | - "outputs": [], |
137 | | - "source": [ |
138 | | - "import asyncio\n", |
139 | | - "\n", |
140 | | - "\n", |
141 | | - "# This is an \"async\" function, like a generator\n", |
142 | | - "async def slow(t: int) -> int:\n", |
143 | | - " print(f\"About to sleep for {t} seconds\")\n", |
144 | | - " await asyncio.sleep(t)\n", |
145 | | - " print(f\"Slept for {t} seconds\")\n", |
146 | | - " return t\n", |
147 | | - "\n", |
148 | | - "\n", |
149 | | - "# Gather runs its arguments in parallel when awaited on\n", |
150 | | - "await asyncio.gather(slow(3), slow(1), slow(2))\n", |
151 | | - "\n", |
152 | | - "# Only works if running in an eventloop already, like IPython or with python -m asyncio\n", |
153 | | - "# Otherwise, use: asyncio.run(...)" |
154 | | - ] |
155 | | - }, |
156 | | - { |
157 | | - "cell_type": "markdown", |
158 | | - "metadata": {}, |
159 | | - "source": [ |
160 | | - "Notice _there are no locks_! We don't have to worry about printing being overleaved, because it's not running at the same time. Only the explicit \"await\" lines \"wait\" at the same time!" |
161 | | - ] |
162 | | - }, |
163 | | - { |
164 | | - "cell_type": "markdown", |
165 | | - "metadata": {}, |
166 | | - "source": [ |
167 | | - "Once we start using Python 3.11 (probably early-mid 2023, based on Pyodide), an asyncio section using TaskGroups will likely be added." |
168 | | - ] |
169 | 115 | } |
170 | 116 | ], |
171 | 117 | "metadata": { |
172 | 118 | "kernelspec": { |
173 | | - "display_name": "Python [conda env:level-up-your-python] *", |
| 119 | + "display_name": "conda-env-level-up-your-python-py", |
174 | 120 | "language": "python", |
175 | 121 | "name": "conda-env-level-up-your-python-py" |
176 | 122 | }, |
|
184 | 130 | "name": "python", |
185 | 131 | "nbconvert_exporter": "python", |
186 | 132 | "pygments_lexer": "ipython3", |
187 | | - "version": "3.10.5" |
| 133 | + "version": "3.14.3" |
188 | 134 | }, |
189 | 135 | "toc-autonumbering": false, |
190 | 136 | "toc-showmarkdowntxt": false, |
|
0 commit comments