线程
1:一个进程至少拥有一个线程,进程提供资源(一块内存)线程负责工作
进程是资源分配的最小单元 为线程提供资源
线程是CPU调度的最小单元 工作
一个进程中可以有多个线程,同一个进程中的线程可以共享进程的资源
由于GIL锁的存在 同一时间一个进程内只有一个线程被CPU调度,所以
计算密集型用多进程
IO密集型用多线程
列表字典的线程安全也依赖于GIL锁
threading 线程模块
t = threading.Thread(target = 函数名,args=(11,22,33,)) 创建一个线程 让这个线程去 干传入的函数的任务,函数需要参数就在args中以元组的形式传入
t.start() 让线程开始工作
2:multiprocess
进程模块
p = multipocessing.Process(target = 函数名,args=(11,22,33,)) 创建一个进程
去干传入的 函数的任务,函数需要参数就args以元组的形式传入
实际上隐含操作是创建进程后会创建一个线程 实际上由这个线程执行任务
p.start() 让进程开始工作
线程才是工作的最小单元
win创建进程是spawn,不在if __name__ == '__main__' 中创建进程会报错
Linux是fork 不需要在if __name__ == '__main__'中创建
mac两种模式都有 在python3.6版本之后默认是spawn
想让在mac中不报错要 multipocessing.set_start_method('fork')
多进程的开销要比多线程大
3:GIL锁 Global Interpreter Lock 全局解释器锁 cpython解释器中特有的 让进程中同一时间只有一个线程被CPU调动
利用CPU多核优势 用多进程
计算密集型操作 要利用CPU的多核优势 用多进程 提高并发
IO密集型操作 利用多线程
4: t= threading.Thread(target = 函数名,args=(11,22,33,))
实际上是创建了一个Thread 类实例
t.start()告诉CPU 子线程准备好了可以被调度
程序开始就有进程创建了一个主线程 然后主线程创建子线程 主线程继续向下走
t.join() 告诉主线程在什么地方等待子线程 子线程执行完毕 后主线程才继续向下走
CPU不是一直执行一个线程 而是分片机制 反复横跳执行不同线程 两个线程同时对一个数据操作可能会造成数据混乱
t.setDeamon(bool) 设置守护线程
决定主线程是否执行完毕后等待子线程
t.setDeamon(bool)必须在 t.start()函数之前
设置为False主线程会在执行后等待子线程执行完毕
设置为True 守护线程则主线程执行完毕程序结束 子线程随之终止
t.setName()设置线程名称 在start()执行之前设置
threading.current_thread().getName()获取当前执行的线程名字
threading.current_thread() 获取当前执行的线程对象
4:自定义线程类
class MyThread(threading.Thread):继承Thread类
def run(self):就是自定义线程要执行的操作
pass
线程安全:
lock_object = thrading.Rlock() 创建锁
t= threading.Thread(target = 函数名例子:add,args=(11,22,33,)) 在add也就是线程要执行的任务函数里加上lock_object.acquire()
def add():
lock_object.acquire() #加锁 线程到这里会申请锁 先到先得 没有申请到的就会等待