@@ -272,9 +272,85 @@ Let's see if we can do better.
272
272
Getting Multiple Pages Asynchronously - With Time Savings
273
273
---------------------------------------------------------
274
274
275
+ We want to take advantage of the asynchronous nature of ``get_page() ``
276
+ and save time.
277
+ We modify our client to use a list with four instances of
278
+ a :term: `task <task> `.
279
+ This allows us to send out requests for all pages we want to retrieve without
280
+ waiting for the answer before asking for the next page:
275
281
276
282
.. literalinclude :: examples/async_client_nonblocking.py
277
283
284
+ The interesting part is in this loop:
285
+
286
+ .. code-block :: python
287
+
288
+ with closing(asyncio.get_event_loop()) as loop:
289
+ for wait in waits:
290
+ tasks.append(get_page(host, port, wait))
291
+ pages = loop.run_until_complete(asyncio.gather(* tasks))
292
+
293
+ We append all return values of ``get_page() `` to our lits of tasks.
294
+ This allows us to send out all request, in our case four, without
295
+ waiting for the answers.
296
+ After sending all of them, we wait for the answers, using:
297
+
298
+ .. code-block :: python
299
+
300
+ loop.run_until_complete(asyncio.gather(* tasks))
301
+
302
+ We used ``loop.run_until_complete() `` already for each call to ``get_page() ``
303
+ in the previous section.
304
+ The difference here is the use of ``asyncio.gather() `` that is called with all
305
+ our tasks in the list ``tasks `` as arguments.
306
+ The ``asyncio.gather(*tasks) `` means for our example with four list entries:
307
+
308
+ .. code-block :: python
309
+
310
+ asyncio.gather(tasks[0 ], tasks[1 ], tasks[2 ], tasks[3 ])
311
+
312
+ So, for a list with 100 tasks it would mean:
313
+
314
+ .. code-block :: python
315
+
316
+ asyncio.gather(tasks[0 ], tasks[1 ], tasks[2 ],
317
+ # 96 more tasks here
318
+ tasks[99 ])
319
+
320
+
321
+ Let's see if we got any faster::
322
+
323
+ async_client_nonblocking.py
324
+ It took 5.08 seconds for a total waiting time of 11.00.
325
+ Waited for 1.00 seconds.
326
+ That's all.
327
+ Waited for 5.00 seconds.
328
+ That's all.
329
+ Waited for 3.00 seconds.
330
+ That's all.
331
+ Waited for 2.00 seconds.
332
+ That's all.
333
+
334
+ Yes! It works.
335
+ The total run time is about five seconds.
336
+ This is the run time for the longest wait.
337
+ Now, we don't have to wait for the sum of ``waits `` but rather for
338
+ ``max(waits) ``.
339
+
340
+ We did quite a bit of work, sending a request and scanning an answer,
341
+ including finding out the encoding.
342
+ There should be a shorter way as these steps seem to be always necessary for
343
+ getting the page content with the right encoding.
344
+ Therefore, in the next section, we will have a look at high-level library
345
+ ``aiohttp `` that can help to make our code shorter.
346
+
347
+ Exercise
348
+ ++++++++
349
+
350
+ Add more waiting times to the list ``waits `` and see how this impacts
351
+ the run times of the blocking and the non-blocking implementation.
352
+ Try (positive) numbers that are all less than five.
353
+ Try numbers greater than five.
278
354
279
355
High-Level Approach with ``aiohttp ``
280
356
------------------------------------
0 commit comments