day 036 线程 -创建,守护线程
线程和进程的关系
1.地址空间和其他资源:进程之间相互独立,同一进程的各线程之间共享,某进程内的线程在其他进程不可见
2.通信:进程间的通信IPC,线程间可以直接写进程数据(如全局变量)来通信需要加锁保证数据一致
3.调度和切换:线程上下文切换比进程快很多
4.在多线程操作系统中,进程不是一个可执行的实体,真正去执行程序的不是进程是线程,进程就是一个线程的容器
线程的主要特点:
1.轻型实体
2.独立调度和分派的基本单位
3.共享进程资源
4.可并发执行
线程的创建
两种方法:
from threading import Thread class MyThread(Thread): def __init__(self,n): super().__init__() self.n=n def run(self): print(self.n) if __name__ == '__main__': t=MyThread(100) t.start() 第二种: from threading import Thread def func(n): print(n) if __name__ == '__main__': t=Thread(target=func,args=(100,)) t.start()
死锁现象及递归锁:
import time from threading import Thread,Lock class MyThread(Thread): def __init__(self,lockA,lockB): super().__init__() self.lockA=lockA self.lockB=lockB pass def run(self): self.f1() self.f2() def f1(self): self.lockA.acquire() print("我拿了A锁") self.lockB. acquire() print("我是一个很好的客户") self.lockB.release() self.lockA.release() def f2(self): self.lockB.acquire() time.sleep(0.1) print("我拿到了B锁") self.lockA.acquire() print("我是好人") self.lockA.release() self.lockB.release() if __name__ == '__main__': lockA=Lock() lockB=Lock() t1=MyThread(lockA,lockB) t1.start() t2=MyThread(lockA,lockB) t2.start() print("我是经理")
递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
守护线程:
无论是进程还是线程,都遵循:守护xx会等待主xx运行完毕后被销毁。需要强调的是:运行完毕并非终止运行
1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束,因为进程执行结束是要回收资源的,所有必须确保你里面的非守护子线程全部执行完毕。