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

一篇文章读懂 Python 多线程

发布时间:2019-09-25 01:31:04 所属栏目:建站 来源:编程派
导读:Threading模块从 Python 1.5.2 版开始呈现,用于加强底层的多线程模块thread。Threading 模块让操纵多线程变得更简朴,而且支持措施同时运行多个操纵。 留意,Python 中的多线程最好用于处理赏罚有关 I/O 的操纵,如从网上下载资源可能从当地读取文件可能目次

当你真正运行这段代码时,你会发明它只是挂起了。究其缘故起因,是由于我们只汇报 threading 模块获取锁。以是当我们挪用第一个函数时,它发明锁已经被获取,随后便把本身挂起了,直到锁被开释,然而这将永久不会产生。

真正的办理步伐是行使重入锁(Re-Entrant Lock)。threading 模块提供的办理步伐是行使RLock函数。即把lock = threading.lock替代为lock = threading.RLock,然后从头运行代码,此刻代码就可以正常运行了。

假如你想在线程中运行以上代码,那么你可以用以下代码代替直接挪用 main函数:

  1. if __name__ == '__main__': 
  2. for i in range(10): 
  3. my_thread = threading.Thread( 
  4. target=main) 
  5. my_thread.start 

每个线程城市运行 main 函数,main 函数则会依次挪用其它两个函数。最终也会发生 10 组功效集。

按时器

Threading 模块有一个优雅的 Timer类,你可以用它来实此刻指按时刻后要产生的举措。它们现实上会启动本身的自界说线程,通过挪用通例线程上的start要领即可运行。你也可以挪用它的cancel要领遏制按时器。值得留意的是,你乃至可以在开始按时器之前打消它。

有一天,我碰着一个非凡的环境:我必要与已经启动的子历程通讯,可是我必要它有超时处理赏罚。固然处理赏罚这种非凡题目有许多差异的要领,不外我最喜好的办理方案是行使 threading 模块的 Timer 类。

在下面这个例子中,我们将行使 ping指令作为演示。在 Linux 体系中,ping 呼吁会一向运行下去直到你手动杀死它。以是在 Linux 天下里,Timer 类就显得很是利便。示譬喻下:

  1. import subprocess 
  2. from threading import Timer 
  3.  
  4. kill = lambda process: process.kill 
  5. cmd = ['ping', 'www.google.com'] 
  6. ping = subprocess.Popen( 
  7. cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
  8.  
  9. my_timer = Timer(5, kill, [ping]) 
  10. try: 
  11. my_timer.start 
  12. stdout, stderr = ping.communicate 
  13. finally: 
  14. my_timer.cancel 
  15. print (str(stdout)) 

这里我们在 lambda 表达式中挪用 kill 杀死历程。接下来启动 ping 呼吁,然后建设 Timer 工具。你会留意到,第一个参数就是必要守候的秒数,第二个参数是必要挪用的函数,紧跟厥后的参数是要挪用函数的入参。在本例中,我们的函数是一个 lambda 表达式,传入的是一个只有一个元素的列表。假如你运行这段代码,它应该会运行 5 秒钟,然后打印出 ping 的功效。

其他线程组件

Threading 模块包括对其他成果的支持。譬喻,你可以建设信号量(Semaphore),这是计较机科学中最迂腐的同步原语之一。根基上,一个信号量打点一个内置的计数器。当你挪用acquire时计数器就会递减,相反当你挪用release时就会递增。按照其计划,计数器的值无法小于零,以是假如正亏得计数器为零时挪用 acquire 要领,该要领将阻塞线程。

译者注:凡是行使信号量时城市初始化一个大于零的值,如 semaphore = threading.Semaphore(2)

另一个很是有效的同步器材就是变乱(Event)。它应承你行使信号(signal)实现线程通讯。在下一节中我们将举一个行使变乱的实例。

最后,在 Python 3.2 中插手了 Barrier工具。Barrier 是打点线程池中的同步原语,在线程池中多条线程必要彼此守候对方。假如要转达 barrier,每一条线程都要挪用wait要领,在其他线程挪用该要领之前列程将会阻塞。所有挪用之后将会同时开释全部线程。

线程通讯

某些环境下,你会但愿线程之间相互通讯。就像先条件到的,你可以通过建设 Event工具到达这个目标。但更常用的要领是行使行列(Queue)。在我们的例子中,这两种方法城市有所涉及。下面让我们看看到底是什么样子的:

  1. import threading 
  2. from queue import Queue 
  3.  
  4. def creator(data, q): 
  5. """ 
  6. 天生用于斲丧的数据,守候斲丧者完成处理赏罚 
  7. """ 
  8. print('Creating data and putting it on the queue') 
  9. for item in data: 
  10. evt = threading.Event 
  11. q.put((item, evt)) 
  12.  
  13. print('Waiting for data to be doubled') 
  14. evt.wait 
  15.  
  16. def my_consumer(q): 
  17. """ 
  18. 斲丧部门数据,并做处理赏罚 
  19.  
  20. 这里所做的只是将输入翻一倍 
  21.  
  22. """ 
  23. while True: 
  24. data, evt = q.get 
  25. print('data found to be processed: {}'.format(data)) 
  26. processed = data * 2 
  27. print(processed) 
  28. evt.set 
  29. q.task_done 
  30.  
  31. if __name__ == '__main__': 
  32. q = Queue 
  33. data = [5, 10, 13, -1] 
  34. thread_one = threading.Thread(target=creator, args=(data, q)) 
  35. thread_two = threading.Thread(target=my_consumer, args=(q,)) 
  36. thread_one.start 
  37. thread_two.start 
  38.  
  39. q.join 

(编辑:湖南网)

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

热点阅读