python3之threading模块(上)

threading模块提供了管理多个线程执行的API。

最简单的用法。就是用一个目标函数实例化一个Thread对象。start()开始工作,join()等待当前线程完成。

  1: import threading
  2: def work():
  3:     print("working")
  4: for i in range(5):
  5:     t = threading.Thread(target=work)
  6:     t.start()
  7:     print("please wait!")
  8:     t.join()

结果

  1: working
  2: please wait!
  3: working
  4: please wait!
  5: working
  6: please wait!
  7: working
  8: please wait!
  9: working
 10: please wait!

当然也可以传递参数。

  1: import threading
  2: def work(i):
  3:     print("%i is working" %i)
  4: for i in range(5):
  5:     t = threading.Thread(target=work,args=(i,))
  6:     t.start()
  7:     print("please wait!")
  8:     t.join()

结果

  1: 0 is working
  2: please wait!
  3: 1 is working
  4: please wait!
  5: 2 is working
  6: please wait!
  7: 3 is working
  8: please wait!
  9: 4 is working
 10: please wait!

确定当前线程

每个Thread实例都有一个带有默认值的名字,也可以传入name参数更改。

  1: import threading
  2: import time
  3: def work():
  4:     print(threading.current_thread().getName(),"starting!")
  5:     time.sleep(0.5)
  6:     print(threading.current_thread().getName(),"end!")
  7: 
  8: t = threading.Thread(name="worker", target=work)
  9: t.start()
 10: print("please wait!")
 11: t.join()

结果

  1: worker starting!
  2: please wait!
  3: worker end!

出于线程安全的考虑,我们下面用logging模块输出消息。

守护线程与非守护线程

一般来说,程序都会等待所有线程完成工作之后才退出。而守护线程可以一直运行而不阻塞主程序的退出。传入daemon=True或者调用setDaemon()方法并提供参数True来构造守护线程。

  1: import threading
  2: import time
  3: import logging
  4: def daemon():
  5:     logging.debug("start")
  6:     time.sleep(0.5)
  7:     logging.debug("exite")
  8: def non_deamon():
  9:     logging.debug("start")
 10:     logging.debug("exit")
 11: logging.basicConfig(
 12:     level=logging.DEBUG,
 13:     format='(%(threadName)-10s) %(message)s',
 14: )
 15: d = threading.Thread(name='deamon', target=daemon, daemon=True)
 16: t = threading.Thread(name="non-deamon", target=non_deamon)
 17: d.start()
 18: t.start()

结果中没有看到守护线程的退出的消息,主程序就已经退出了。

  1: (deamon    ) start
  2: (non-deamon) start
  3: (non-deamon) exit

要等待一个守护线程结束,需要使用join()方法。默认下,join会无限阻塞,但可以传入浮点值。在时间内线程即使未完成,join也会强制返回。

  1: import threading
  2: import time
  3: import logging
  4: def daemon():
  5:     logging.debug("start")
  6:     time.sleep(0.5)
  7:     logging.debug("exite")
  8: def non_deamon():
  9:     logging.debug("start")
 10:     logging.debug("exit")
 11: logging.basicConfig(
 12:     level=logging.DEBUG,
 13:     format='(%(threadName)-10s) %(message)s',
 14: )
 15: d = threading.Thread(name='deamon', target=daemon, daemon=True)
 16: t = threading.Thread(name="non-deamon", target=non_deamon)
 17: d.start()
 18: d.join(0.2)
 19: t.start()

结果还是没有看到守护线程的结束退出的消息。

  1: (deamon    ) start
  2: (non-deamon) start
  3: (non-deamon) exit

枚举所有线程

threading.enumerate()会返回一个Thread实例的一个列表。由于等待当前主程序终止会引入一种死锁的情况,所以跳过这个线程等待。注意根据电脑配置,合理调节线程睡眠时间,否则会由于缺少logging参数而报错。

  1: import threading
  2: import time
  3: import logging
  4: import random
  5: def worker():
  6:     pause = random.randint(1, 5) / 2
  7:     logging.debug("sleeping %0.2f" % pause)
  8:     time.sleep(pause)
  9:     logging.debug("end!")
 10: logging.basicConfig(
 11:     level=logging.DEBUG,
 12:     format='(%(threadName)-10s) %(message)s',
 13: )
 14: for i in range(3):
 15:     t = threading.Thread(target=worker, daemon=True)
 16:     t.start()
 17: # 拿到当前主线程
 18: main_thread = threading.main_thread()
 19: for t in threading.enumerate():
 20:     if t is main_thread:
 21:         continue
 22:     logging.debug("joining %s" % t.getName())
 23:     t.join()
上述程序各个线程执行的顺序image

输出顺序可能不一样,

  1: (Thread-1  ) sleeping 0.50
  2: (Thread-2  ) sleeping 1.50
  3: (Thread-3  ) sleeping 2.00
  4: (MainThread) joining Thread-1
  5: (Thread-1  ) end!
  6: (MainThread) joining Thread-2
  7: (Thread-2  ) end!
  8: (MainThread) joining Thread-3
  9: (Thread-3  ) end!
原文地址:https://www.cnblogs.com/haoqirui/p/10321194.html