线程

线程理论

  什么是线程:指令的执行过程。

        在进程中存在线程,进程如果没有线程无法运行,进程只是负责提供内存资源,线程真正进入CPU,是CPU最小的运行单位。多线程就是为了一个进程执行多个任务。

        线程的创建销毁被进程快,且不像进程那样内存隔离,可以不需要额外操作就可以实现数据共享。

        并发的时候,多进程加多线程;多核中也可以应用多线程。

线程的两种创建方式(重点)main可写可不写

 1 from threading import Thread
 2 第一种
 3 def f1(n):
 4     print(1+n)
 5 
 6 def f2(n):
 7     print(2)
 8 
 9 if __name__ == '__main__':
10     t1 = Thread(target=f1,args=(0,))  #与进程创建相同
11     t2 = Thread(target=f2,args=(0,))  #与进程创建相同
12     t1.start()
13     t2.start()
14 print('主线程')
15 第二种
16 class MyThread(Thread):
17     def __init__(self,name):
18         super().__init__()
19         self.name = name
20 
21     def run(self):
22         print(self.name)
23 
24 if __name__ == '__main__':
25     t= MyThread('cc')
26     t.start()
27     print('主线程')
线程的两种创建方式

查看线程pid线程(了解)

  os.getpid(),显示都是同一个进程号

线程可以直接数据共享             等待线程执行完毕的方法为join(),用法同进程

与进程效率对比      创建时间差了将近百倍

线程空间不是隔离的

  Io密集型切换提高代码效率;计算密集型切换降低代码效率。

  计算密集型,运行时间加长,此时多线程无法应用多核技术,所有多线程此时反而比多进程慢

守护线程

  守护线程等待所有非守护线程结束才结束,一旦别人都结束,而守护进程没结束的话也自杀

  进程只守护主进程

线程锁/互锁(重点)

 1 from threading import Lock,Thread
 2 import time
 3 
 4 num = 100
 5 def f1():
 6     global num
 7     temp = num
 8     temp -= 1
 9     time.sleep(1)
10     num = temp
11 
12 if __name__ == '__main__':
13     t_list = []
14 
15     for i in range(10):
16         t = Thread(target=f1,)
17         t.start()
18         t_list.append(t)
19 
20     [t.join() for tt in t_list]
21 
22     print('主线程的num:',num)
23 此时无法得到90,十个线程的操作在相同,瞬间开启,
24 每个人线程拿到的temp可能都是100,最后赋值回去为99,可能是拿到99,变成了99
25 
26 num = 100
27 
28 
29 def f1(loc):
30     global num   #只是声明一个变量,不会拿到数据,不存在赋值
31     loc.acquire()
32     temp = num
33     temp -= 1
34     time.sleep(0.1)
35     num = temp
36     loc.release()
37 
38 
39 if __name__ == '__main__':
40     t_list = []
41     t_loc = Lock()
42     for i in range(10):
43         t = Thread(target=f1,args=(t_loc,) )
44         t.start()
45         t_list.append(t)
46 
47     [t.join() for tt in t_list]
48 
49     print('主线程的num:', num)
50 
51     #加锁,用法同进程锁
线程锁

死锁(重点)

  在锁的代码中再完成地嵌套一个锁时发生,

  A中嵌套一个完整的B,B中嵌套一个完整的A,两个在想抢对方已有的锁的时候都会卡死,相互锁死

递归锁(重点)

  破除死锁,同一把锁多个形式,RLock()

  内含计数器,创建一次就加一,释放一个就减一,为零才可以抢

GIL锁:

  在全局的cpython解释器上加的一把锁

  解释器用于解释自己的代码为二进制
       同一时间,只能有一个线程可以进入cpython解释器,导致py不能使用多核技术。想多线程并发依旧是可以搞的,但是就需要开多进程来实现了,因为就是又多开了一个解释器。
        线程可以节约io密集型程序的时间,计算密集型则不行。一般进程按照cpu的个数开。
  子进程不能input,因为输入台只能由主进程使用,输出内容各个进程都可以,但是并发输出可能会打印混乱。 子线程可以输入,因为同属一个进程。

原文地址:https://www.cnblogs.com/shachengcc1/p/11337214.html