python学习Day38--进程与线程

一、回顾

1、生产者消费者模型

  主要为了解决强耦合的问题

2、队列 from multiprocessing import Queue

  先进先出,队列本身是安全的

  可连接的队列:from multiprocessing import JoinableQueue

  task_done( )  每消费一个数据,就返回一个标识

  join( )             接收task_done返回的标识,以便可以知道队列中的数据什么时候被消费完了

3、管道(了解)

  本身不安全的

  队列 = 管道 + 锁

  from multiprocessing import Pipe

  con1,con2 = Pipe( )

  con1可以收发数据,con2也可以收发数据(全双工)

4、多进程之间共享内存数据

  from multiprocessing import Manager,Value

扫描二维码关注公众号,回复: 11080776 查看本文章

5、进程池

  from multiprocessing import Pool

  p.map(func,iterable)

  p.apply(func,args=( ))

  p.apply_async(func, args=( ),callback=None)

    close:不再接收新的任务,准备关闭

    join:等待进程池中的所有进程执行完任务

  池中的进程是守护进程,主进程的代码执行完毕,守护进程就结束了

  在进程池中的回调函数是主进程调用的,和子进程无关。

二、线程

1、线程的概念

  线程被称作轻量级的进程。 GIL:全局解释锁(只有Cpython解释器才有)

  计算机的执行单位以线程为单位,计算机的最小可执行是线程。

  进程是资源分配的基本单位。线程是可执行的基本单位,是可被调度的基本单位。

  线程不可以自己独立拥有资源。线程的执行,必须依赖于所属进程中的资源。

  线程又分为用户级线程和内核级线程:(了解)

    用户级线程:对于程序员来说的,这样的线程完全被程序员控制执行,调度。

    内核级线程:对于计算机内核来说的,这样的线程完全被内核控制调度。

2、线程和进程的比较

  进程由:代码段、数据段、PCB组成

  线程由:代码段、数据段、TCB组成

(1)初识线程

 1 # *******************初识线程**********************开始
 2 import threading
 3 from threading import Thread
 4 import time
 5 
 6 def func():
 7     print("这是一个子线程")
 8     time.sleep(2)
 9 
10 if __name__ == '__main__':
11     t = Thread(target=func,args=())
12     t.start()
13 # *******************初识线程**********************结束

(2)线程与进程对比

  ① CPU切换进程要比CPU切换线程慢很多,在pyth中,如果IO操作过多的化话,使用多线程最好了。

 1 # *******************线程与进程法比较**********************开始
 2 from multiprocessing import Process
 3 from threading import Thread
 4 import time
 5 
 6 def func():
 7     pass
 8 
 9 if __name__ == '__main__':
10     start = time.time()
11     for i in range(100):
12         p = Process(target=func)
13         p.start()
14     print("开100个进程的时间:",time.time()-start)
15 
16     start = time.time()
17     for i in range(100):
18         t = Thread(target=func)
19         t.start()
20     print("开100个线程的时间:", time.time() - start)
21 # *******************线程与进程法比较**********************结束
对比1

  ② 在同一个进程内,所有线程共享这个进程的pid,也就是说所有线程共享所属进程的所有资源和内存地址。、

 1 from multiprocessing import Process
 2 from threading import Thread
 3 import time,os
 4 
 5 def func(name):
 6     print("我是一个%s,我的pid是%s" % (name,os.getpid()))
 7 
 8 if __name__ == '__main__':
 9     print("我是main,我的的pid是:%s" % os.getpid())
10     for i in range(10):
11         p = Process(target=func,args=('进程',))
12         p.start()
13 
14     for i in range(10):
15         p = Thread(target=func,args=('线程',))
16         p.start()
对比3

  ③ 在同一个进程内,所有线程共享该进程的全局变量。

 1 # *******************线程与进程的对比3**********************开始
 2 from multiprocessing import Process
 3 from threading import Thread
 4 import time,os
 5 
 6 def func():
 7     global num
 8     num -= 1
 9 
10 if __name__ == '__main__':
11     num = 100
12     t = Thread(target=func)
13     t.start()
14     time.sleep(1)
15     print(num) # 99
16 # *******************线程与进程的对比3**********************结束
对比3

(3)线程之间的数据安全问题

  因为有GIL锁的存在,在Cpython中,没有真正的线程并行。但是有真正的多进程并行。

  当你的任务是计算密集的情况下,使用多进程好。

  【总结】在Cpython中,IO密集用多线程,计算密集用多进程。

3、死锁

(1)什么是死锁?如下代码

 1 # *******************什么是死锁**********************开始
 2 from multiprocessing import Process
 3 from threading import Thread,Lock
 4 import time,os
 5 
 6 def man(l_tot,l_pap):
 7     l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
 8     print('alex在厕所上厕所')
 9     time.sleep(1)
10     l_pap.acquire()# 男的拿纸资源
11     print('alex拿到卫生纸了!')
12     time.sleep(0.5)
13     print('alex完事了!')
14     l_pap.release()# 男的先还纸
15     l_tot.release()# 男的还厕所
16 
17 def woman(l_tot,l_pap):
18     l_pap.acquire()  # 女的拿纸资源
19     print('小雪拿到卫生纸了!')
20     time.sleep(1)
21     l_tot.acquire()  # 是女的获得厕所资源,把厕所锁上了
22     print('小雪在厕所上厕所')
23     time.sleep(0.5)
24     print('小雪完事了!')
25     l_tot.release()  # 女的还厕所
26     l_pap.release()  # 女的先还纸
27 
28 
29 if __name__ == '__main__':
30     l_tot = Lock()
31     l_pap = Lock()
32     t_man = Thread(target=man,args=(l_tot,l_pap))
33     t_woman = Thread(target=woman,args=(l_tot,l_pap))
34     t_man.start()
35     t_woman.start()
36 # *******************什么是死锁**********************结束

(2)解决死锁问题——递归锁

 1 # *******************解决死锁**********************开始
 2 '''RLock是递归锁——是无止尽的锁,但是所有锁都有一个共同的钥匙'''
 3 
 4 from threading import Thread,RLock
 5 import time,os
 6 
 7 def man(l_tot,l_pap):
 8     l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
 9     print('alex在厕所上厕所')
10     time.sleep(1)
11     l_pap.acquire()# 男的拿纸资源
12     print('alex拿到卫生纸了!')
13     time.sleep(0.5)
14     print('alex完事了!')
15     l_pap.release()# 男的先还纸
16     l_tot.release()# 男的还厕所
17 
18 def woman(l_tot,l_pap):
19     l_pap.acquire()  # 女的拿纸资源
20     print('小雪拿到卫生纸了!')
21     time.sleep(1)
22     l_tot.acquire()  # 是女的获得厕所资源,把厕所锁上了
23     print('小雪在厕所上厕所')
24     time.sleep(0.5)
25     print('小雪完事了!')
26     l_tot.release()  # 女的还厕所
27     l_pap.release()  # 女的先还纸
28 
29 
30 if __name__ == '__main__':
31     l_tot = l_pap = RLock()
32     t_man = Thread(target=man,args=(l_tot,l_pap))
33     t_woman = Thread(target=woman,args=(l_tot,l_pap))
34     t_man.start()
35     t_woman.start()
36 # *******************解决死锁**********************结束
递归锁

 【小结——锁】

  递归锁:RLock( )可以有无止尽的锁,但是会哟一把万能钥匙

  互斥所:Lock( )  一把钥匙配一把锁

  GIL:全局解释器锁,锁的是线程,是解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访问CPU。

4、使用条件机制调度线程

  from threading import Thread, Condition

  Conditon( )涉及4个方法:

    acquire( ) # 加锁

    release( )# 解锁

    wait( ) # 是指给wait发一个信号,让wait变成不阻塞

    notify(int) # 是指给wait发一个信号,让wait变成不阻塞(int是指给多少wait发信号)

 1 # *******************Conditon**********************开始
 2 from threading import Condition,Thread
 3 import time
 4 
 5 def func(con,i):
 6     con.acquire()
 7     print(123)
 8     con.wait() # 线程执行到这里,会阻塞住,等待notify发送信号,来唤醒此线程
 9     print(456)
10     con.release()
11     print("第%s个线程开始执行了!" % i)
12 
13 if __name__ == '__main__':
14     con = Condition()
15     for i in range(10):
16         t = Thread(target=func,args=(con,i))
17         t.start()
18 
19     while 1:
20         num = int(input("》》》"))
21         con.acquire()
22         con.notify(num) # 发送一个信号给num个正在阻塞在wait的线程,让这些线程正常执行
23         con.release()
24 # *******************Conditon**********************结束
Conditon

5、线程里的定时器

1 # *******************定时器**********************开始
2 from threading import Timer
3 
4 def func():
5     print("开始执行了")
6 
7 Timer(3,func).start() # 3秒后执行func
8 # *******************定时器**********************结束

6、线程里的事件机制

  from threading import Event(与多进程的事件机制一样)

7、线程里的信号量

  from threading import Semaphore(与多进程里的信号量一样)

8、线程里的守护线程

  守护线程是根据主进程执行结束才结束

  守护线程不是根据主线程的代码执行结束而结束

  主线程会等待普通线程执行结束,再结束

  守护线程会等待主线程结束,再结束。

 1 # *******************守护线程**********************开始
 2 from threading import Thread
 3 import time
 4 
 5 def func():
 6     time.sleep(2)
 7     print(123)
 8 
 9 def func1():
10     time.sleep(3)
11     print(456)
12 
13 if __name__ == '__main__':
14     t = Thread(target=func)
15     t.daemon = True # 守护进程
16     t.start()
17     t1 = Thread(target=func1)
18     t1.start()
19 # *******************守护线程**********************结束

猜你喜欢

转载自www.cnblogs.com/fengxb1213/p/12761879.html