基础概念

http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html(较好解释)

  • 进程 : 程序的动态执行,是程序的进口和出口,进程是资源分配的最小单位,进程由自己的独立内存空间、数据栈等,不同进程只能使用进程间通信,而不能直接共享信息。

  • 线程 :是CPU调度的最小单位,一个进程中的各个线程之间共享同一块数据空间。

  • 互斥锁 : 防止多个线程同时读写某一块内存区域,进程的某一块内存区域,只允许一个线程占有,当被某一个线程占有,就锁上;

  • 线程有开始、顺序执行和结束3部分,有一个自己的指令指针,记录运行到什么地方。线程的运行可能被抢占(中断)或暂时被挂起(睡眠),从而让其他线程运行,这叫作让步。

  • 线程一般是并发执行的。正是由于这种并行和数据共享的机制,使得多个任务的合作变得可能。实际上,在单CPU系统中,真正的并发并不可能,每个线程会被安排成每次只运行一小会儿,然后就把CPU让出来,让其他线程运行。

  • 对于操作系统来说,一个任务就是一个进程,开启多个任务就是多进程。

有些进程不止可以同时做一件事,比如Word可以同时打字、检查拼写、打印等。在一个进程内部,要同时做多件事,就需要同时运行多个线程。(进程中的多线程)

线程在执行过程中与进程还是有区别的。每个独立线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能独立执行,必须依存在进程中,由进程提供多个线程执行控制。

多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂交替运行,看起来就像同时执行一样。当然,真正同时执行多线程需要多核CPU才能实现。

同时执行多个任务的方法:

  1. 多个进程可以一起执行多个任务
  2. 启动一个进程,在一个进程内启动多个线程,这样多个线程也可以一起执行多个任务。
  3. 启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,不过这种模型过于复杂,实际很少采用。

总而言之,多线程是多个相互关联的线程的组合,多进程是多个互相独立的进程的组合。线程是最小的执行单元,进程至少由一个线程组成。
}FV1]SK7(0ISPE3353~~X9L.png

如何选择并发编程模式

小概念

![O%`(VZ)0_9_QP%IXL8@ZJ9.png
需要大量的读取硬盘->io ; 大量的计算->cpu

全局解释器锁

QU7X_0L~GCT@DDF0_]J(~QR.png
AQJ5Z2@L68FLF3X$~)F@FRS.png
![RJ%{L5R8W{FIBEB@CYCYNY.png
![}@QHDP[SHWV0LO%IFD[)32.png](https://cdn.nlark.com/yuque/0/2021/png/12357578/1632646113925-3fd705ce-dde7-4bf0-9ca3-e05da5123c1c.png#clientId=ub6637562-e1fc-4&from=paste&height=354&id=uc9939369&margin=%5Bobject%20Object%5D&name=%60%7D%40QHDP%5BSHWV0LO%25IFD%5B%2932.png&originHeight=707&originWidth=1126&originalType=binary&ratio=1&size=337354&status=done&style=none&taskId=u11adaea0-d18d-40a7-9a9e-e5a7fdfa6a5&width=563)(requests库不支持多协程)<br />![YHV0ZFKFGDQKY~3K7XX4FL.png](https://cdn.nlark.com/yuque/0/2021/png/12357578/1632646152639-7d43700f-bffe-4c80-84c9-8c240889b917.png#clientId=ub6637562-e1fc-4&from=paste&height=318&id=u7c1686b4&margin=%5Bobject%20Object%5D&name=YHV0ZFKFGDQKY~3%60K7XX4FL.png&originHeight=636&originWidth=1159&originalType=binary&ratio=1&size=191681&status=done&style=none&taskId=u6aedab10-0c12-4673-87d9-45339ea5861&width=579.5)
![90U)DY)1K`VSE4AU_CSSJS.png

  1. Python虚拟机的访问由全局解释器锁(Global Interpreter Lock, GIL)控制,这个锁能保证同一时刻只有一个线程运行。
  2. 由于GIL python只能运行一个线程,本身是不支持多线程的;
  3. IO密集型:释放锁;达到多线程
  4. CPU密集型 :多进程

python线程模块

python-多线程编程 - 图4
python-多线程编程 - 图5

创建线程

`Z$7(4O185W9A){SUIGT~LN.png

  1. import threading #引入线程模块
  2. threading.Thread(target=eud_url.requests_edu,args=(url,)
  3. #target->函数名!只是函数名,不是调用函数()没有括号, args=元组,函数的参数变量
  4. 只有一个的情况下(变量,)要有,
  5. thread.start()
  6. thread.join()
  7. #线程之间的执行顺序是无序的;
  8. 多线程中join()的用法https://www.cnblogs.com/cnkai/p/7504980.html

多线程爬虫

  1. import requests
  2. urls =[
  3. f"https://src.sjtu.edu.cn/list/?page={page}"
  4. for page in range(1,21)
  5. ]
  6. #print(urls)
  7. def requests_edu(url):
  8. r=requests.get(url=url,verify=None)
  9. print(url,len(r.text))
  10. #requests_edu(urls[0])
  11. import threading
  12. import time
  13. import eud_url
  14. def single_thread():
  15. print("single_thread begin:")
  16. for url in eud_url.urls:
  17. eud_url.requests_edu(url)
  18. def multi_thread():
  19. print("multi_thread begin:")
  20. threads = []
  21. for url in eud_url.urls:
  22. threads.append(
  23. threading.Thread(target=eud_url.requests_edu,args=(url,))
  24. )
  25. for thread in threads:
  26. thread.start()
  27. for thread in threads:
  28. thread.join()
  29. if __name__ == '__main__':
  30. start=time.time()
  31. single_thread()
  32. end=time.time()
  33. print("singel thread cost: %s"%(end-start))
  34. start=time.time()
  35. multi_thread()
  36. end=time.time()
  37. print("multi thread cost: %s"%(end-start))

python-多线程编程 - 图7
python-多线程编程 - 图8