@@ -264,9 +264,6 @@ everything in parallel. ::
264
264
import requests
265
265
266
266
def get_webpage(url):
267
- """
268
- Some blocking function.
269
- """
270
267
page = requests.get(url)
271
268
return page
272
269
@@ -354,6 +351,74 @@ official documentation.
354
351
Threading
355
352
---------
356
353
354
+ The standard library comes with a `threading `_ module that allows a user to
355
+ work with multiple threads manually.
356
+
357
+ Running a function in another thread is as simple as passing a callable and
358
+ it's arguments to `Thread `'s constructor and then calling `start() `::
359
+
360
+ from threading import Thread
361
+ import requests
362
+
363
+ def get_webpage(url):
364
+ page = requests.get(url)
365
+ return page
366
+
367
+ some_thread = Thread(get_webpage, 'http://google.com/')
368
+ some_thread.start()
369
+
370
+ To wait until the thread has terminated, call `join() `::
371
+
372
+ some_thread.join()
373
+
374
+ After calling `join() `, it is always a good idea to check whether the thread is
375
+ still alive (because the join call timed out)::
376
+
377
+ if some_thread.is_alive():
378
+ print("join() must have timed out.")
379
+ else:
380
+ print("Our thread has terminated.")
381
+
382
+ Because multiple threads have access to the same section of memory, sometimes
383
+ there might be situations where two or more threads are trying to write to the
384
+ same resource at the same time or where the output is dependent on the sequence
385
+ or timing of certain events. This is called a `data race `_ or race condition.
386
+ When this happens, the output will be garbled or you may encounter problems
387
+ which are difficult to debug. A good example is this `stackoverflow post `_.
388
+
389
+ The way this can be avoided is by using a `Lock `_ that each thread needs to
390
+ acquire before writing to a shared resource. Locks can be acquired and released
391
+ through either the contextmanager protocol (`with ` statement), or by using
392
+ `acquire() ` and `release() ` directly. Here is a (rather contrived) example::
393
+
394
+ from threading import Lock, Thread
395
+
396
+ file_lock = Lock()
397
+
398
+ def log(msg):
399
+ with file_lock:
400
+ open('website_changes.log', 'w') as f:
401
+ f.write(changes)
402
+
403
+ def monitor_website(some_website):
404
+ """
405
+ Monitor a website and then if there are any changes, log them to disk.
406
+ """
407
+ while True:
408
+ changes = check_for_changes(some_website)
409
+ if changes:
410
+ log(changes)
411
+
412
+ websites = ['http://google.com/', ... ]
413
+ for website in websites:
414
+ t = Thread(monitor_website, website)
415
+ t.start()
416
+
417
+ Here, we have a bunch of threads checking for changes on a list of sites and
418
+ whenever there are any changes, they attempt to write those changes to a file
419
+ by calling `log(changes) `. When `log() ` is called, it will wait to acquire
420
+ the lock with `with file_lock: `. This ensures that at any one time, only one
421
+ thread is writing to the file.
357
422
358
423
Spawning Processes
359
424
------------------
@@ -371,3 +436,6 @@ Multiprocessing
371
436
.. _`David Beazley's` : http://www.dabeaz.com/GIL/gilvis/measure2.py
372
437
.. _`concurrent.futures` : https://docs.python.org/3/library/concurrent.futures.html
373
438
.. _`Future` : https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future
439
+ .. _`threading` : https://docs.python.org/3/library/threading.html
440
+ .. _`stackoverflow post` : http://stackoverflow.com/questions/26688424/python-threads-are-printing-at-the-same-time-messing-up-the-text-output
441
+ .. _`data race` : https://en.wikipedia.org/wiki/Race_condition
0 commit comments