Python多线程编程学习笔记
写在前面
1. 多进程
-
多任务
- 多任务的优势:充分利用CPU资源,提高程序的执行效率
- 多任务是指在同一时间内执行多个任务
- 多任务的表现形式
- 并发:在一段时间内交替去执行多个任务
- 并行:在一段时间内真正的同时一起执行多个任务
-
进程
- 进程(Process)是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位
- 一个程序至少有一个进程,程序是静态的,进程是动态的
-
多进程完成多任务
-
p = multiprocessing.Process(target, name, group)
-
p.start()
启动进程 -
测试
from multiprocessing import Process import time # 唱歌 def sing(): for i in range(3): print('唱歌...') time.sleep(0.5) # 跳舞 def dance(): for i in range(3): print('跳舞...') time.sleep(0.5) if __name__ == '__main__': p1 = Process(target=sing) p2 = Process(target=dance) p1.start() p2.start()
-
-
进程执行带有参数的任务
-
args参数的使用
-
kwargs参数的使用
from multiprocessing import Process import time import os # 唱歌 def sing(num): print('唱歌进程的pid:', os.getpid()) print('唱歌父进程的pid:', os.getppid()) for i in range(num): print('唱歌...') time.sleep(0.5) # 跳舞 def dance(num2): print('跳舞进程的pid:', os.getpid()) print('跳舞父进程的pid:', os.getppid()) for i in range(num2): print('跳舞...') time.sleep(0.5) if __name__ == '__main__': print('主进程的pid:', os.getpid()) p1 = Process(target=sing, args=(5,)) p2 = Process(target=dance, kwargs={'num2': 2}) p1.start() p2.start()
-
-
获取进程的编号
- 获取当前进程的编号:
os.getpid()
- 获取当前父进程的编号:
os.getppid()
- 获取当前进程的编号:
-
进程的注意点
-
主进程会等待所有的子进程执行结束后再结束
-
设置守护主进程:主进程不会等待子进程结束就会结束
子进程对象.daemon = True
-
2. 多线程
-
为什么要使用多线程:
进程是分配资源的最小单位,一旦创建一个进程就会分配一定的资源。线程是程序执行的最小单位,一个进程中最少有一个线程来负责执行程序。线程自己不拥有系统资源,它可以与同属一个进程的其他线程共享进程所拥有的全部资源。
-
多线程完成多任务:跟进程一毛一样,只不过模块不一样。
from threading import Thread
-
线程执行带有参数的任务:跟进程一毛一样
-
主线程和子线程的结束顺序:也跟进程一毛一样
只不过设置守护线程的方法有两种:
- 在创建的时候,传递daemon参数
- 创建后,设置daemon
-
线程间的执行顺序
- 线程之间的执行是无序的,由CPU调度
- 获取当前的线程信息:
threading.current_thread()
-
进程和线程对比
-
关系对比:
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
-
区别对比:
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
- 线程不能够独立执行,必须依存在进程中
-
优缺点对比:
-
进程优缺点:
优点:可以用多核
缺点:资源开销大
-
线程优缺点:
优点:资源开销小
缺点:不能使用多核
-
-
3. 补充
- join:等待该线程执行完之后,才接着运行主线程后面的语句。
- 线程的返回是不能用return的,也就是说多线程的时候,不能通过return获取函数的返回值,需要传入一个记录返回值的列表,然后将函数的结果放入列表中。
- GIL 限制了 Python 多线程的性能不会像我们预期的那样。GIL:全局解释器锁,Global Interpreter Lock。GIL参考链接,参考链接2
- 我们该如何解决GIL锁的问题呢?
- 更换cpython为jpython(不建议)
- 使用多进程完成多线程的任务
- 在使用多线程可以使用c语言去实现
- 什么时候会释放GIL?
- 遇到像 i/o操作这种 会有时间空闲情况 造成cpu闲置的情况会释放Gil
- 会有一个专门ticks进行计数 一旦ticks数值达到100 这个时候释放Gil锁 线程之间开始竞争Gil锁(说明: ticks这个数值可以进行设置来延长或者缩减获得Gil锁的线程使用cpu的时间)
- 互斥锁和Gil锁的关系?
- Gil锁 : 保证同一时刻只有一个线程能使用到cpu
- 互斥锁 : 多线程时,保证修改共享数据时有序的修改,不会产生数据修改混乱
- 我们该如何解决GIL锁的问题呢?
- 互斥锁
threading.Lock()
,执行时需要lock.acquire()
,结束后需要lock.release()
,这样有锁的线程才能操作。
我的CSDN:https://blog.csdn.net/qq_21579045
我的博客园:https://www.cnblogs.com/lyjun/
我的Github:https://github.com/TinyHandsome
纸上得来终觉浅,绝知此事要躬行~
欢迎大家过来OB~
by 李英俊小朋友