欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第三十三天- 线程创建、join、守护线程、死锁

程序员文章站 2023-10-15 16:14:48
1.线程,线程创建 概念:在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线。流水线的工作需要电源,电源就相当于c ......

 

1.线程,线程创建

  概念:在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线。流水线的工作需要电源,电源就相当于cpu。

  所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位

  多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。

 

  创建:

  线程创建方式一:

第三十三天- 线程创建、join、守护线程、死锁
 1 from multiprocessing import process
 2 from threading import thread
 3 
 4 
 5 def func(n):
 6     print('xxxxx')
 7     print('>>>',n)
 8 
 9 
10 if __name__ == '__main__':
11 
12     # p = process(target=func,args=(1,))
13     # p.start()
14 
15     t = thread(target=func,args=(1,))  # 直接创建
16     t.start()
17 
18     print('主线程结束')
view code

  面向对象创建:

第三十三天- 线程创建、join、守护线程、死锁
 1 from threading import thread
 2 
 3 
 4 # 面向对象创建
 5 class mythread(thread):  # 继承thread父类
 6 
 7     def __init__(self,xx):
 8         super().__init__()
 9         self.xx = xx
10 
11     def run(self):  # 必须有run,覆盖父类run中的pass
12         print(self.xx)
13         print('我重置父类方法')
14 
15     def func1(self): # 写其他方法
16         print('我是func1')
17 
18 
19 if __name__ == '__main__':
20 
21     t1 = mythread('xx')
22     t1.start()  # 默认执行run
23     t1.func1()  # 调用其他方法
24 #
25 
26 from multiprocessing import process
27 from threading import thread
view code

 

 

2.thread类方法

  join方法:

  主线程等待join子线程执行完毕后才执行

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import thread
 3 
 4 
 5 def func(n):
 6     time.sleep(n)
 7     print('我是子线程')
 8 
 9 
10 if __name__ == '__main__':
11 
12     t = thread(target=func,args=(1,))
13     t.start()
14 
15     t.join() # 等待子线程执行结束
16     print('我是主线程,子线程结束再执行我')
join

  

  其他方法:

 1 ''
 2 thread实例对象的方法
 3   # isalive(): 返回线程是否活动的。
 4   # getname(): 返回线程名。
 5   # setname(): 设置线程名。
 6 
 7 threading模块提供的一些方法:
 8   # threading.currentthread(): 返回当前的线程变量。
 9   # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
10   # threading.activecount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
11 '''
第三十三天- 线程创建、join、守护线程、死锁
 1 import time, threading
 2 from threading import thread, current_thread
 3 
 4 
 5 def func():
 6     time.sleep(2)
 7     print('子线程,名字是:', current_thread().getname())  # 返回线程名
 8     print('子线程,id是:', current_thread().ident)  # 返回线程id
 9 
10 
11 if __name__ == '__main__':
12 
13     for i in range(10):
14         t = thread(target=func, )
15         t.start()
16 
17     print(threading.enumerate())  # 返回一个包含正在运行的list
18     print(threading.activecount())  # 返回正在运行的线程数量,等同len(threading.enumerate())
19 
20     print('主线程结束')
其他方法示例

 

 

3.守护线程、事件

  守护线程:

  主进程结束,守护进程跟着结束,再执行非守护进程
  主线程要等待所有非守护线程运行结束才会结束(因为他们属于同一进程)
  需注意:运行结束并非终止运行

  xxx.setdaemon(true)  或者 xxx.daemon = true

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import thread
 3 from multiprocessing import process
 4 
 5 
 6 def func1():
 7     time.sleep(3)
 8     print('任务1结束')
 9 
10 
11 def func2():
12     time.sleep(2)
13     print('任务2结束')
14 
15 
16 if __name__ == '__main__':
17 
18     # p1 = process(target=func1,)
19     # p2 = process(target=func2,)
20     # # p1.daemon = true
21     # p2.daemon = true
22     # p1.start()
23     # p2.start()
24     #
25     # print('主进程结束')
26 
27     t1 = thread(target=func1,)
28     t2 = thread(target=func2,)
29     # t1.setdaemon(true) # 只打印出 主线程和t2 因为t2时间比t1小
30     t2.setdaemon(true)  # 会正常打印出所有 因为t1时间大于t2
31     t1.start()
32     t2.start()
33 
34     print('主线程结束')
守护线程与守护进程

  

  事件: 

  event.isset():返回event的状态值;
  event.wait():如果 event.isset()==false将阻塞线程;
  event.set(): 设置event的状态值为true,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
  event.clear():恢复event的状态值为false。

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import event
 3 
 4 e = event()  # 默认false状态
 5 print(e.isset())  # 事件当前状态
 6 
 7 e.set()  # 改变成ture
 8 print(e.isset())
 9 
10 print('稍等...')
11 # e.clear()  # 将e的状态改为false
12 e.wait()  # 如果 event.isset()==false将阻塞线程
13 
14 if e.isset() == true:
15     time.sleep(1)
16     print('滴滴滴,上车吧...')
事件代码示例

 

 

4.线程间数据问题

  开启一个线程所需要的时间要远小于开启一个进程

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from multiprocessing import process
 3 from threading import thread
 4 
 5 
 6 def func(i):
 7     return '我是任务%s'%i
 8 
 9 
10 if __name__ == '__main__':
11 
12     # 多线程
13     t_list = []
14     t_start_time = time.time()
15     for i in range(10):
16         t = thread(target=func,args=(i,))
17         t_list.append(t)
18         t.start()
19 
20     [tt.join() for tt in t_list]
21     t_end_time = time.time()
22     t_dif_time = t_end_time - t_start_time
23 
24     # 多进程
25     p_list = []
26     p_start_time = time.time()
27     for i in range(10):
28         p = process(target=func,args=(i,))
29         p_list.append(p)
30         p.start()
31 
32     [pp.join() for pp in p_list]
33     p_end_time = time.time()
34     p_dif_time = p_end_time - p_start_time
35     # 结果受cpu影响
36     
37     print('多线程耗时:',t_dif_time)
38     print('多进程耗时:',p_dif_time)
39     print('主线程结束')
40 
41 '''
42 多线程耗时: 0.0020008087158203125
43 多进程耗时: 0.4188823699951172
44 '''
多线程和多进程效率对比

  线程之间共享进程资源(全局变量在多个线程之间共享),但也会导致数据不但全问题

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import thread
 3 
 4 num = 100
 5 
 6 def func():
 7     global num
 8     tep = num  # tep替换 模拟多步操作
 9     time.sleep(0.001)  # 模拟延迟
10     tep -= 1
11     num = tep
12 
13 
14 if __name__ == '__main__':
15 
16     t_list = []
17     for i in range(100):
18         t = thread(target=func,)
19         t_list.append(t)
20         t.start()
21 
22     [tt.join() for tt in t_list]
23 
24     print('主线程的num',num)  # 打印出不是100可知数据是共享的
25 
26 # 理论上应该是0,但多线程是并发执行的,会出现上一个线程还在运算中时,下一个线程并未等待它返回值
27 # 也拿了原来的值进来运算,所以打印出了91,92,93不等,可知多线程数据是不安全的
28 '''
29 主线程的num 92
30 '''
验证多线程之间数据共享 数据不安全问题

  加锁解决多线程数据不安全问题

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import thread,lock
 3 
 4 num = 100
 5 def func(lock,i):
 6     global num
 7     lock.acquire()  # 加锁
 8     
 9     tep = num
10     time.sleep(0.001)  # 模拟延迟
11     tep -= 1
12     num = tep
13 
14     lock.release()  # 释放
15 
16 
17 if __name__ == '__main__':
18     t_list = []
19     lock = lock()
20     for i in range(100):
21         t = thread(target=func,args=(lock,i))
22         t_list.append(t)
23         t.start()
24 
25     [tt.join() for tt in t_list]
26     print('主线程num',num)
27 
28 '''
29 主线程num 0
30 '''
lock

 

  信号量semaphore

第三十三天- 线程创建、join、守护线程、死锁
 1 import time,random
 2 from threading import thread,semaphore
 3 
 4 
 5 def func(i,s):
 6     s.acquire()
 7     print('%s张烧饼'%i)
 8     time.sleep(random.randint(1,3))
 9     s.release()
10     # 出来一个进去一个 始终6个  最后不足6个就都进来了
11 
12 
13 if __name__ == '__main__':
14     s = semaphore(6)  # 与lock类似,不过可限制最大连接数,如这里同时只有6个线程可以获得semaphore
15     for i in range(28):
16         t = thread(target=func,args=(i,s,))
17         t.start()
semaphore

 

 

5.死锁和递归锁

  死锁现象:有多个锁时,双方互相等待对方释放对方手里拿到的那个锁导致死锁   

第三十三天- 线程创建、join、守护线程、死锁

第三十三天- 线程创建、join、守护线程、死锁
 1 import time
 2 from threading import thread,lock
 3 
 4 
 5 def func1(lock_a,lock_b):
 6     lock_a.acquire()
 7     print('张全蛋拿到了a锁')
 8     time.sleep(0.5)
 9     lock_b.acquire()
10     print('张全蛋拿到了b锁')
11     lock_b.release()
12     lock_a.release()
13 
14 
15 def func2(lock_a,lock_b):
16     lock_b.acquire()
17     print('赵二狗拿到了b锁')
18     lock_a.acquire()
19     print('赵二狗拿到了a锁')
20     lock_a.release()
21     lock_b.release()
22 
23 
24 if __name__ == '__main__':
25 
26     lock_a = lock()
27     lock_b = lock()
28     t1 = thread(target=func1,args=(lock_a,lock_b,))
29     t2 = thread(target=func2,args=(lock_a,lock_b,))
30     t1.start()
31     t2.start()
死锁现象

 

  递归锁:rlock 

  rlock管理一个内置的计数器,
  每当调用acquire()时内置计数器-1;
  调用release() 时内置计数器+1;
  计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

 

第三十三天- 线程创建、join、守护线程、死锁

 

第三十三天- 线程创建、join、守护线程、死锁
 1 # 递归锁解决死锁现象
 2 import time
 3 from threading import thread,lock,rlock
 4 
 5 
 6 def func1(lock_a,lock_b):
 7     lock_a.acquire()
 8     print('张全蛋拿到了a锁')
 9     time.sleep(0.5)
10     lock_b.acquire()
11     print('张全蛋拿到了b锁')
12     lock_b.release()
13     lock_a.release()
14 
15 
16 def func2(lock_a,lock_b):
17     lock_b.acquire()
18     print('赵二狗拿到了b锁')
19     lock_a.acquire()
20     print('赵二狗拿到了a锁')
21     lock_a.release()
22     lock_b.release()
23 
24 
25 if __name__ == '__main__':
26 
27     # lock_a = lock()
28     # lock_b = lock()
29     lock_a = lock_b = rlock()
30     t1 = thread(target=func1,args=(lock_a,lock_b,))
31     t2 = thread(target=func2,args=(lock_a,lock_b,))
32     t1.start()
33     t2.start()
递归锁解决死锁现象