加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

一篇文章读懂 Python 多线程

发布时间:2019-09-25 00:35:44 所属栏目:建站 来源:编程派
导读:Threading模块从 Python 1.5.2 版开始出现,用于增强底层的多线程模块thread。Threading 模块让操作多线程变得更简单,并且支持程序同时运行多个操作。 注意,Python 中的多线程最好用于处理有关 I/O 的操作,如从网上下载资源或者从本地读取文件或者目录
副标题[/!--empirenews.page--]

Threading模块从 Python 1.5.2 版开始出现,用于增强底层的多线程模块thread。Threading 模块让操作多线程变得更简单,并且支持程序同时运行多个操作。

一篇文章读懂 Python 多线程

注意,Python 中的多线程最好用于处理有关 I/O 的操作,如从网上下载资源或者从本地读取文件或者目录。如果你要做的是 CPU 密集型操作,那么你需要使用 Python 的multiprocessing模块。这样做的原因是,Python 有一个全局解释器锁 (GIL),使得所有子线程都必须运行在同一个主线程中。正因为如此,当你通过多线程来处理多个 CPU 密集型任务时,你会发现它实际上运行的更慢。因此,我们将重点放在那些多线程最擅长的领域:I/O 操作!

线程简介

多线程能让你像运行一个独立的程序一样运行一段长代码。这有点像调用子进程(subprocess),不过区别是你调用的是一个函数或者一个类,而不是独立的程序。在我看来,举例说明更有助于解释。下面来看一个简单的例子:

  1. import threading 
  2.  
  3. def doubler(number): 
  4. """ 
  5. 可以被线程使用的一个函数 
  6. """ 
  7. print(threading.currentThread.getName + 'n') 
  8. print(number * 2) 
  9. print 
  10.  
  11. if __name__ == '__main__': 
  12. for i in range(5): 
  13. my_thread = threading.Thread(target=doubler, args=(i,)) 
  14. my_thread.start 

这里,我们导入 threading 模块并且创建一个叫 doubler的常规函数。这个函数接受一个值,然后把这个值翻一番。它还会打印出调用这个函数的线程的名称,并在最后打印一行空行。然后在代码的最后一块,我们创建五个线程并且依次启动它们。在我们实例化一个线程时,你会注意到,我们把 doubler 函数传给target参数,同时也给 doubler 函数传递了参数。Args参数看起来有些奇怪,那是因为我们需要传递一个序列给 doubler 函数,但它只接受一个变量,所以我们把逗号放在尾部来创建只有一个参数的序列。

需要注意的是,如果你想等待一个线程结束,那么需要调用 join方法。

当你运行以上这段代码,会得到以下输出内容:

  1. Thread-1 
  2.  
  3.  
  4. Thread-2 
  5.  
  6.  
  7. Thread-3 
  8.  
  9.  
  10. Thread-4 
  11.  
  12.  
  13. Thread-5 
  14.  

当然,通常情况下你不会希望输出打印到标准输出。如果不幸真的这么做了,那么最终的显示效果将会非常混乱。你应该使用 Python 的 logging 模块。它是线程安全的,并且表现出色。让我们用 logging模块修改上面的例子并且给我们的线程命名。代码如下:

  1. import logging 
  2. import threading 
  3.  
  4. def get_logger: 
  5. logger = logging.getLogger("threading_example") 
  6. logger.setLevel(logging.DEBUG) 
  7.  
  8. fh = logging.FileHandler("threading.log") 
  9. fmt = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s' 
  10. formatter = logging.Formatter(fmt) 
  11. fh.setFormatter(formatter) 
  12.  
  13. logger.addHandler(fh) 
  14. return logger 
  15.  
  16. def doubler(number, logger): 
  17. """ 
  18. 可以被线程使用的一个函数 
  19. """ 
  20. logger.debug('doubler function executing') 
  21. result = number * 2 
  22. logger.debug('doubler function ended with: {}'.format( 
  23. result)) 
  24.  
  25. if __name__ == '__main__': 
  26. logger = get_logger 
  27. thread_names = ['Mike', 'George', 'Wanda', 'Dingbat', 'Nina'] 
  28. for i in range(5): 
  29. my_thread = threading.Thread( 
  30. target=doubler, name=thread_names[i], args=(i,logger)) 
  31. my_thread.start 

代码中最大的改变就是加入了 get_logger函数。这段代码将创建一个被设置为调试级别的日志记录器。它将日志保存在当前目录(即脚本运行所在的目录)下,然后设置每行日志的格式。格式包括时间戳、线程名、日志记录级别以及日志信息。

在 doubler 函数中,我们把 print语句换成 logging 语句。你会注发现,在创建线程时,我们给 doubler 函数传入了 logger 对象。这样做的原因是,如果在每个线程中实例化 logging 对象,那么将会产生多个 logging 单例(singleton),并且日志中将会有很多重复的内容。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读