VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • Python3标准库:threading进程中管理并发操作

1. threading进程中管理并发操作

threading模块提供了管理多个线程执行的API,允许程序在同一个进程空间并发的运行多个操作。

1.1 Thread对象

要使用Thread,最简单的方法就是用一个目标函数实例化一个Thread对象,并调用start()让它开始工作。


	
  1. import threading
  2.  
  3. def worker():
  4. """thread worker function"""
  5. print('Worker')
  6.  
  7. threads = []
  8. for i in range(5):
  9. t = threading.Thread(target=worker)
  10. threads.append(t)
  11. t.start()

输出有5行,每一行都是"Worker"。

如果能够创建一个线程,并向它传递参数告诉它要完成什么工作,那么这会很有用。任何类型的对象都可以作为参数传递到线程。下面的例子传递了一个数,线程将打印出这个数。


	
  1. import threading
  2.  
  3. def worker(num):
  4. """thread worker function"""
  5. print('Worker: %s' % num)
  6.  
  7. threads = []
  8. for i in range(5):
  9. t = threading.Thread(target=worker, args=(i,))
  10. threads.append(t)
  11. t.start()

现在这个整数参数会包含在各线程打印的消息中。

1.2 确定当前线程

使用参数来标识或命名线程很麻烦,也没有必要。每个Thread实例都有一个带有默认值的名,该默认值可以在创建线程时改变。如果服务器进程中有多个服务线程处理不同的操作,那么在这样的服务器进程中,对线程命名就很有用。


	
  1. import threading
  2. import time
  3.  
  4. def worker():
  5. print(threading.current_thread().getName(), 'Starting')
  6. time.sleep(0.2)
  7. print(threading.current_thread().getName(), 'Exiting')
  8.  
  9. def my_service():
  10. print(threading.current_thread().getName(), 'Starting')
  11. time.sleep(0.3)
  12. print(threading.current_thread().getName(), 'Exiting')
  13.  
  14. t = threading.Thread(name='my_service', target=my_service)
  15. w = threading.Thread(name='worker', target=worker)
  16. w2 = threading.Thread(target=worker) # use default name
  17.  
  18. w.start()
  19. w2.start()
  20. t.start()

调试输出的每一行中包含有当前线程的名。线程名列中有"Thread-1"的行对应未命名的线程w2。

大多数程序并不使用print来进行调试。logging模块支持将线程名嵌入到各个日志消息中(使用格式化代码%(threadName)s)。通过把线程名包含在日志消息中,就能跟踪这些消息的来源。


	
  1. import logging
  2. import threading
  3. import time
  4.  
  5. def worker():
  6. logging.debug('Starting')
  7. time.sleep(0.2)
  8. logging.debug('Exiting')
  9.  
  10. def my_service():
  11. logging.debug('Starting')
  12. time.sleep(0.3)
  13. logging.debug('Exiting')
  14.  
  15. logging.basicConfig(
  16. level=logging.DEBUG,
  17. format='[%(levelname)s] (%(threadName)-10s) %(message)s',
  18. )
  19.  
  20. t = threading.Thread(name='my_service', target=my_service)
  21. w = threading.Thread(name='worker', target=worker)
  22. w2 = threading.Thread(target=worker) # use default name
  23.  
  24. w.start()
  25. w2.start()
  26. t.start()

而且logging是线程安全的,所以来自不同线程的消息在输出中会有所区分。

1.3 守护与非守护线程

到目前为止,示例程序都在隐式地等待所有线程完成工作之后才退出。不过,程序有 时会创建一个线程作为守护线程(daemon),这个线程可以一直运行而不阻塞主程序退出。 如果一个服务不能很容易地中断线程,或者即使让线程工作到一半时中止也不会造成数据 损失或破坏(例如,为一个服务监控工具生成“心跳”的线程),那么对于这些服务,使用 守护线程就很有用。要标志一个线程为守护线程,构造线程时便要传入daemon=True或 者要调用它的setDaemon()方法并提供参数True。默认情况下线程不作为守护线程。


	
  1. import threading
  2. import time
  3. import logging
  4.  
  5. def daemon():
  6. logging.debug('Starting')
  7. time.sleep(0.2)
  8. logging.debug(