python多线程学习笔记(超详细)

简介: pythonthreading多线程一. Threading简介首先看下面的没有用Threading的程序import threading,time  def fun():  s = 0  for i in range(30):  s += i  time.
python
threading
多线程

一. Threading简介

首先看下面的没有用Threading的程序

  1. import threading,time 
  2.  
  3. def fun(): 
  4. s = 0 
  5. for i in range(30): 
  6. s += i 
  7. time.sleep(0.1
  8. print(s) 
  9.  
  10. if __name__ == '__main__'
  11. t = time.time() 
  12. fun() 
  13. fun() 
  14. print(time.time()-t) 
  15.  
  16. >>>  
  17. 435 
  18. 435 
  19. 6.023701906204224 
  20. [Finished in 6.6s] 

如果使用线程会有什么样的效果呢

  1. import threading,time 
  2.  
  3. def fun(): 
  4. s = 0 
  5. for i in range(30): 
  6. s += i 
  7. time.sleep(0.1
  8. print(s) 
  9.  
  10. if __name__ == '__main__'
  11. # 创建了一个线程列表,包含2个线程 
  12. ths = [threading.Thread(target=fun) for i in range(2)] 
  13. for th in ths: 
  14. th.start() 
  15. t = time.time() 
  16. for th in ths: 
  17. th.join() 
  18. print(time.time()-t) 
  19.  
  20.  
  21. >>>  
  22. 435 
  23. 435 
  24. 3.116874933242798 
  25. [Finished in 3.7s] 

这说明两个线程几乎是同时进行的


二. Threading的应用进阶

  1. join(timeout)用来实现线程等待。
    被调用join()方法的线程会一直阻塞调用者的线程,
    直到自己结束(正常结束,或引发未处理异常),
    或超出timeout的时间。

  1. import threading,time 
  2.  
  3. class MyThread(threading.Thread): 
  4.  
  5. def run(self): 
  6. for i in range(30): 
  7. print('threading:',i) 
  8. time.sleep(0.1
  9.  
  10. if __name__ == '__main__'
  11. t = MyThread() 
  12. t.start() 
  13. t.join(1
  14. for i in range(10): 
  15. print('Main:',i) 
  16. time.sleep(0.1
  17.  
  18. >>>  
  19. threading: 0 
  20. threading: 1 
  21. threading: 2 
  22. 主线程等待t这个线程0.1秒后也开始运行 
  23. Main: 0 
  24. threading: 3 
  25. Main: 1 
  26. threading: 4 
  27. Main: 2 
  28. threading: 5 
  29. Main: 3 
  30. threading: 6 
  31. Main: 4 
  32. threading: 7 
  33. Main: 5 
  34. threading: 8 
  35. Main: 6 
  36. threading: 9 
  37. Main: 7 
  38. Main: 8 
  39. Main: 9 
  40. [Finished in 2.0s] 

注意每次运行的结果都不太一样

2)daemon属性
被设定为后台运行的线程,会在主程序退出时主动自杀。
设置为后台运行线程的方法是:设置线程的daemon属性为True

  1. import threading,time 
  2.  
  3. def dmn(): 
  4. print('dmn start...'
  5. time.sleep(2
  6. print('dmn end.'
  7.  
  8. def ndmn(): 
  9. print('ndmn start...'
  10. time.sleep(1
  11. print('ndmn end.'
  12.  
  13. d = threading.Thread(target=dmn) 
  14. d.daemon = True 
  15. n = threading.Thread(target=ndmn) 
  16. print('start...'
  17. d.start() 
  18. n.start() 
  19. print('end.'
  20.  
  21. >>> 
  22. start... 
  23. dmn start... 
  24. ndmn start... 
  25. end. 
  26. ndmn end. 
  27. [Finished in 1.3s] 

由上面打印的结果我们可以看到dmn线程设置为后台线程后,它的 print('dmn end.') 语句并不没有执行,这是因为后台线程在主线程结束后会自杀,所以主线程执行完后,dmn线程没能说出自己的“遗言”。
作为对比,我将daemon设为False,结果如下

  1. ... 
  2.  
  3. d = threading.Thread(target=dmn)  
  4. d.daemon = False  
  5. ... 
  6.  
  7. >>> 
  8. start... 
  9. dmn start... 
  10. ndmn start... 
  11. end. 
  12. ndmn end. 
  13. dmn end. 
  14. [Finished in 2.5s] 
  1. 线程同步
    1 )指令锁 threading.Lock

acquire尝试获得锁定,进入阻塞状态。
acquire(blocking=True, timeout=-1))

release释放获得锁定(资源使用完后)
release()

  1. import threading,time,random 
  2.  
  3. share = 4  
  4. lock = threading.Lock() #初始化指令锁 
  5.  
  6. class MyThread(threading.Thread): 
  7. def __init__(self,i): 
  8. super().__init__() 
  9. self.i = i 
  10.  
  11. def run(self): 
  12. global share 
  13. for d in range(2): 
  14. lock.acquire() 
  15. print(share) 
  16. share += self.i 
  17. time.sleep(random.random()) 
  18. print('+',self.i,'=',share) 
  19. lock.release() 
  20.  
  21. if __name__ == '__main__'
  22. t = MyThread(2
  23. tt = MyThread(6
  24. t.start() 
  25. tt.start() 
  26.  
  27. >>> 
  28. 4 
  29. + 2 = 6 
  30. 6 
  31. + 6 = 12 
  32. 12 
  33. + 2 = 14 
  34. 14 
  35. + 6 = 20 
  36. [Finished in 2.9s] 

为了更好的感受指令锁的作用,将acquire和release去掉后结果如下

  1. ... 
  2. def run(self):  
  3. global share  
  4. for d in range(2):  
  5. # lock.acquire()  
  6. print(share)  
  7. share += self.i  
  8. time.sleep(random.random())  
  9. print('+',self.i,'=',share)  
  10. # lock.release()  
  11. ... 
  12.  
  13. >>> 
  14. 4 
  15. 6 
  16. + 6 = 12 
  17. 12 
  18. + 2 = 18 
  19. 18 
  20. + 6 = 20 
  21. + 2 = 20 
  22. [Finished in 2.2s] 

比较后可以知道,加了指令锁后可以清楚地知道对共享资源share操作的具体情况

2 )条件变量threading.Condition
属性

  • 实例化时,可指定锁。

  • acquire()

  • release()

  • wait(timeout=None)
    释放锁,进入等待阻塞,
    直到唤醒或超时。

  • notify(n=1)
    唤醒等待该条件变量的线程。默认1个。

  • notify_all()
    唤醒等待该条件变量的所有线程。

实现严格的依照次序操作的线程之间的通信。
典型的实例:生产者/消费者(只有生产后,才能消费)。
线程之间可以互相通知,以达到默契的配合。
条件变量可以使用默认的锁或用户创建的锁来工作。

话不多说看代码

  1. import threading,time 
  2.  
  3. share = 0 
  4.  
  5. share_cond = threading.Condition() 
  6.  
  7. # 生产者 
  8. class ProThread(threading.Thread): 
  9. def __init__(self): 
  10. super().__init__() 
  11. self.name = 'Produce' 
  12.  
  13. def run(self): 
  14. global share 
  15. if share_cond.acquire(): 
  16. while True
  17. if not share: # 若没东西了,即开始生产 
  18. share += 1 
  19. print(self.name,share) 
  20. share_cond.notify() #唤醒消费者?这个是我自己的理解  
  21. share_cond.wait() 
  22. time.sleep(1
  23.  
  24. # 消费者 
  25. class CustomThread(threading.Thread): 
  26. def __init__(self): 
  27. super().__init__() 
  28. self.name = 'Custom' 
  29.  
  30. def run(self): 
  31. global share 
  32. if share_cond.acquire(): 
  33. while True
  34. if share: 
  35. share -= 1 # 若有东西就买买买 
  36. print(self.name,share) 
  37. share_cond.notify() #唤醒生产者,同上,仅是个人理解,如有错请告知,谢谢 
  38. share_cond.wait() 
  39. time.sleep(1
  40.  
  41. if __name__ == '__main__'
  42. t = ProThread() 
  43. tt = CustomThread() 
  44. t.start() 
  45. tt.start() 
  46.  
  47. >>> 
  48. Produce 1 
  49. Custom 0 
  50. Produce 1 
  51. Custom 0 
  52. Produce 1 
  53. Custom 0 
  54. ... 
  55. ... 
  56. ... 

上面的结果会一直重复执行下去

3 ) 信号量threading.Semaphore

属性

  • 实例化时,指定使用量。

  • 其内置计数器,锁定时+1,
    释放时-1,计数器为0则阻塞。

  • acquire(blocking=True,timeout=None)

  • release()释放锁。

  1. import threading,time 
  2.  
  3. sema = threading.Semaphore(2
  4.  
  5. class MyThread(threading.Thread): 
  6. def __init__(self,name): 
  7. super().__init__() 
  8. self.name = name 
  9.  
  10. def run(self): 
  11. if sema.acquire(): 
  12. print(self.name,'Had got resource.'
  13. time.sleep(1
  14. sema.release() 
  15. print(self.name,'Had released resource.'
  16.  
  17. if __name__ == '__main__'
  18. ths = [MyThread(str(i)+'Sema') for i in range(5)] 
  19. for th in ths: 
  20. th.start() 
  21.  
  22. >>> 
  23. 0Sema Had got resource. 
  24. 1Sema Had got resource. 
  25. 2Sema Had got resource. 
  26. 1Sema Had released resource. 
  27. 3Sema Had got resource. 
  28. 0Sema Had released resource. 
  29. 3Sema Had released resource. 
  30. 4Sema Had got resource. 
  31. 2Sema Had released resource. 
  32. 4Sema Had released resource. 
  33. [Finished in 3.6s] 

4 ) 线程通信threading.Event

  • 其管理一个内部标志.实现一个线程,唤醒其它线程。

  • set() 设置内部标志为True

  • clear() 设置内部标志为False

  • wait(timeout)
    阻塞线程,到内部标志为True。

  1. import threading,time 
  2.  
  3. event = threading.Event() 
  4.  
  5. class MyThreadWait(threading.Thread): 
  6. def run(self): 
  7. self.name = 'Wait Thread' 
  8. print(self.name,"Wait..."
  9. event.wait() 
  10. print(self.name,"Start..."
  11. event.clear() 
  12.  
  13. class MyThreadMain(threading.Thread): 
  14. def run(self): 
  15. time.sleep(3
  16. print('Main thread set event flag!'
  17. event.set() 
  18.  
  19. if __name__ == '__main__'
  20. thw = MyThreadWait() 
  21. thm = MyThreadMain() 
  22. thw.start() 
  23. thm.start() 
  24.  
  25. >>> 
  26. Wait Thread Wait... 
  27. Main thread set event flag! 
  28. Wait Thread Start... 
  29. [Finished in 3.6s] 

好了,大概就是这些了,其他的以后再补充,另外感谢麦子学院提供的免费课程~~~真心不是打广告哈哈
为了避嫌,顺便感谢一下imooc,极客学院~很多都是从这些造福人类的网站学到的。
另附上麦子学院的视频教程,毕竟要学会感恩嘛
http://www.maiziedu.com/course/644-9663/


marsggbo笔记出品,必属精品哈哈

目录
相关文章
|
3月前
|
安全 数据处理 开发者
Python中的多线程编程:从入门到精通
本文将深入探讨Python中的多线程编程,包括其基本原理、应用场景、实现方法以及常见问题和解决方案。通过本文的学习,读者将对Python多线程编程有一个全面的认识,能够在实际项目中灵活运用。
|
2月前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
2月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
2月前
|
Java Unix 调度
python多线程!
本文介绍了线程的基本概念、多线程技术、线程的创建与管理、线程间的通信与同步机制,以及线程池和队列模块的使用。文章详细讲解了如何使用 `_thread` 和 `threading` 模块创建和管理线程,介绍了线程锁 `Lock` 的作用和使用方法,解决了多线程环境下的数据共享问题。此外,还介绍了 `Timer` 定时器和 `ThreadPoolExecutor` 线程池的使用,最后通过一个具体的案例展示了如何使用多线程爬取电影票房数据。文章还对比了进程和线程的优缺点,并讨论了计算密集型和IO密集型任务的适用场景。
123 4
|
3月前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
2月前
|
监控 JavaScript 前端开发
python中的线程和进程(一文带你了解)
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生分享技术心得的地方。如果你从我的文章中有所收获,欢迎关注我,我将持续更新更多优质内容,你的支持是我前进的动力!🎉🎉🎉
33 0
|
2月前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
77 0
|
3月前
|
Java Python
python知识点100篇系列(16)-python中如何获取线程的返回值
【10月更文挑战第3天】本文介绍了两种在Python中实现多线程并获取返回值的方法。第一种是通过自定义线程类继承`Thread`类,重写`run`和`join`方法来实现;第二种则是利用`concurrent.futures`库,通过`ThreadPoolExecutor`管理线程池,简化了线程管理和结果获取的过程,推荐使用。示例代码展示了这两种方法的具体实现方式。
python知识点100篇系列(16)-python中如何获取线程的返回值
|
3月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
79 1
|
3月前
|
Ubuntu Linux Python
Ubuntu学习笔记(六):ubuntu切换Anaconda和系统自带Python
本文介绍了在Ubuntu系统中切换Anaconda和系统自带Python的方法。方法1涉及编辑~/.bashrc和/etc/profile文件,更新Anaconda的路径。方法2提供了详细的步骤指导,帮助用户在Anaconda和系统自带Python之间进行切换。
164 1