多线程基础知识

使用 threading 模块,可以通过创建新的 threading.Thread 并为其分配执行的函数来启动新的执行线程:

import threading

def foo():
  print "Hello threading!"

my_thread = threading.Thread(target=foo)

target 参数引用要运行的函数(或可调用对象)。在 Thread 对象上调用 start 之前,线程不会开始执行。

开始一个线程

my_thread.start() # prints 'Hello threading!'

现在 my_thread 已经运行并终止,再次调用 start 会产生一个 RuntimeError。如果你想将你的线程作为一个守护进程运行,传递 daemon=True kwarg,或者在调用 start() 之前将 my_thread.daemon 设置为 True,会导致你的 Thread 作为守护进程在后台静默运行。

加入主题

如果你将一个大工作分成几个小工作并想要同时运行它们,但需要等待所有这些工作完成才能继续,Thread.join() 是你正在寻找的方法。

例如,假设你要下载网站的多个页面并将其编译为单个页面。你这样做:

import requests
from threading import Thread
from queue import Queue

q = Queue(maxsize=20)
def put_page_to_q(page_num):
    q.put(requests.get('http://some-website.com/page_%s.html' % page_num)

def compile(q):
    # magic function that needs all pages before being able to be executed
    if not q.full():
        raise ValueError
    else:
        print("Done compiling!")

threads = []
for page_num in range(20):
     t = Thread(target=requests.get, args=(page_num,))
     t.start()
     threads.append(t)

# Next, join all threads to make sure all threads are done running before
# we continue. join() is a blocking call (unless specified otherwise using 
# the kwarg blocking=False when calling join)
for t in threads:
    t.join()

# Call compile() now, since all threads have completed
compile(q)

仔细看看 join() 如何工作可以在这里找到。

创建自定义线程类

使用 threading.Thread 类我们可以继承新的自定义 Thread 类。我们必须在子类中覆盖 run 方法。

from threading import Thread
import time

class Sleepy(Thread):

    def run(self):
        time.sleep(5)
        print("Hello form Thread")

if __name__ == "__main__":
    t = Sleepy()
    t.start()      # start method automatic call Thread class run method.
    # print 'The main program continues to run in foreground.'
    t.join()
    print("The main program continues to run in the foreground.")