进程是最小的资源单位,线程是最小的执行单位

一、进程

进程:就是一个程序在一个数据集上的一次动态执行过程。

进程由三部分组成:

1、程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成

2、数据集:数据集则是程序在执行过程中所需要使用的资源

3、进程控制块:进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感

知进程存在的唯一标志。

二、线程                                                                                                                                                            

  Threading用于提供线程相关的操作。线程是应用程序中工作的最小单元,它被包含在进程之中,是进程中的实际运作单位。一

条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

1、实现线程并发

示例1:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading  #线程
 6 import time
 7
 8 def Hi(num): #有一个参数
 9     print("hello %s" %num)
10     time.sleep(3)
11
12 if __name__ == '__main__':
13
14     t1=threading.Thread(target=Hi,args=(10,))  #创建了一个线程对象t1,10做为一个参数,传给num
15     t1.start()
16
17     t2=threading.Thread(target=Hi,args=(9,))   #创建了一个线程对象t2,9做为一个参数,传给num
18     t2.start()
19
20     print("ending.........")  #主线程输出ending

执行结果:

1 hello 10    #子线程
2 hello 9     #子线程
3 ending.........   #主线程
4 #上面三个同时出来,再停顿三秒才结束
5 Process finished with exit code 0  #停顿3秒才结束

示例2:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def music():
 9     print("begin to listen %s"%time.ctime())
10     time.sleep(3)
11     print("stop to listen %s" %time.ctime())
12
13 def game():
14     print("begin to play game %s"%time.ctime())
15     time.sleep(5)
16     print("stop to play game %s" %time.ctime())
17
18 if __name__ == '__main__':
19
20     t1=threading.Thread(target=music)
21     t1.start()
22     t2=threading.Thread(target=game)
23     t2.start()

执行结果:

1 #总共花了5秒时间
2
3 begin to listen Sat Jan 14 12:34:43 2017
4 begin to play game Sat Jan 14 12:34:43 2017  #1、先打印2个
5
6 stop to listen Sat Jan 14 12:34:46 2017      #2、等待3秒再打印一个
7
8 stop to play game Sat Jan 14 12:34:48 2017   #3、再等待2秒,打印一个

2、使用join方法

示例1:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def music():
 9     print("begin to listen %s"%time.ctime())
10     time.sleep(3)
11     print("stop to listen %s" %time.ctime())
12
13 def game():
14     print("begin to play game %s"%time.ctime())
15     time.sleep(5)
16     print("stop to play game %s" %time.ctime())
17
18 if __name__ == '__main__':
19
20     t1=threading.Thread(target=music)
21     t2=threading.Thread(target=game)
22
23     t1.start()  #运行实例的方法
24     t2.start()
25
26     t1.join()   #子线程对象调用join()方法
27     t2.join()
28
29     print("ending")  #在主线程中

执行结果:

begin to listen Sat Jan 14 12:58:34 2017
begin to play game Sat Jan 14 12:58:34 2017  #先打印2个

stop to listen Sat Jan 14 12:58:37 2017      #等待3秒,再打印一个

stop to play game Sat Jan 14 12:58:39 2017   #等待2秒,再打印两个
ending  

示例2:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def music():
 9     print("begin to listen %s"%time.ctime())
10     time.sleep(3)
11     print("stop to listen %s" %time.ctime())
12
13 def game():
14     print("begin to play game %s"%time.ctime())
15     time.sleep(5)
16     print("stop to play game %s" %time.ctime())
17
18 if __name__ == '__main__':
19
20     t1=threading.Thread(target=music)
21     t2=threading.Thread(target=game)
22
23     t1.start()  #运行实例的方法
24     t2.start()
25
26     t1.join()   #t1线程不结束,谁都不往下走
27
28     print("ending")  

执行结果:

1 begin to listen Sat Jan 14 13:06:07 2017
2 begin to play game Sat Jan 14 13:06:07 2017  #先打印这两行
3
4 stop to listen Sat Jan 14 13:06:10 2017      #再等待3秒打印这两行
5 ending
6
7 stop to play game Sat Jan 14 13:06:12 2017   #再等待2秒打印这行

示例3:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def music():
 9     print("begin to listen %s"%time.ctime())
10     time.sleep(3)
11     print("stop to listen %s" %time.ctime())
12
13 def game():
14     print("begin to play game %s"%time.ctime())
15     time.sleep(5)
16     print("stop to play game %s" %time.ctime())
17
18 if __name__ == '__main__':
19
20     t1=threading.Thread(target=music)
21     t2=threading.Thread(target=game)
22
23     t1.start()  #运行实例的方法
24     t2.start()
25
26     t2.join()
27
28     print("ending")  #在主线程中

执行结果:

1 begin to listen Sat Jan 14 13:12:34 2017     #先打印这两行
2 begin to play game Sat Jan 14 13:12:34 2017
3
4 stop to listen Sat Jan 14 13:12:37 2017      #等待3秒,打印这一行
5
6 stop to play game Sat Jan 14 13:12:39 2017   #等待2秒,打印这两行
7 ending

示例4:并没有实现并发(失去多线程的意义)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def music():
 9     print("begin to listen %s"%time.ctime())
10     time.sleep(3)
11     print("stop to listen %s" %time.ctime())
12
13 def game():
14     print("begin to play game %s"%time.ctime())
15     time.sleep(5)
16     print("stop to play game %s" %time.ctime())
17
18 if __name__ == '__main__':
19
20     t1=threading.Thread(target=music)
21     t2=threading.Thread(target=game)
22
23     t1.start()
24
25     t1.join()
26     t2.start()
27
28     t2.join()
29
30     print("ending")  #在主线程中

执行结果:

1 begin to listen Sat Jan 14 13:26:18 2017    #先打印条1行
2
3 stop to listen Sat Jan 14 13:26:21 2017     #等待3秒再打印2行
4 begin to play game Sat Jan 14 13:26:21 2017
5
6 stop to play game Sat Jan 14 13:26:26 2017  #等待5秒打印2行
7 ending

三、线程的两种调用方式                                                                                                                                       

  threading 模块建立在 thread 模块之上。thread 模块以低级、原始的方式来处理和控制线程,而 threading 模块通过对 thread

进行二次封装,提供了更方便的 api 来处理线程。

1、直接调用(推荐写法)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8
 9 def sayhi(num):  # 定义每个线程要运行的函数
10
11     print("running on number:%s" % num)
12
13     time.sleep(3)
14
15
16 if __name__ == '__main__':
17     t1 = threading.Thread(target=sayhi, args=(1,))  # 生成一个线程实例
18     t2 = threading.Thread(target=sayhi, args=(2,))  # 生成另一个线程实例
19
20     t1.start()  # 启动线程
21     t2.start()  # 启动另一个线程
22
23     print(t1.getName())  # 获取线程名
24     print(t2.getName())

执行结果:

1 running on number:1
2 running on number:2
3 Thread-1
4 Thread-2

2、继承式调用(有些编程人员会用这种写法,也要能看懂。不推荐这种写法)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 #自己定制一个MyThread的类
 9 class MyThread(threading.Thread):
10     def __init__(self, num):
11         threading.Thread.__init__(self)
12         self.num = num
13
14     def run(self):  # 定义每个线程要运行的函数
15
16         print("running on number:%s" % self.num)
17
18         time.sleep(3)
19
20
21 if __name__ == '__main__':
22     t1 = MyThread(1)  #继承这个类,把1这个参数,传给num ,t1就是个线程对象
23     t2 = MyThread(2)
24     t1.start()
25     t2.start()
26
27     print("ending......")

执行结果:

1 running on number:1
2 running on number:2
3 ending......

四、 threading.thread的实例方法  

1、join&Daemon方法

示例1:没有用Daemon方法示例

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     for t in threads:
31         t.start()
32
33     print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 13:44:10 2017
2 Begin recording the python线程! Sat Jan 14 13:44:10 2017
3 all over Sat Jan 14 13:44:10 2017         #先打印三个出来; 主线程结束了
4
5 end listening Sat Jan 14 13:44:13 2017    #等待3秒,打印这1个; 子线程还没有结束,会继续往下运行
6
7 end recording Sat Jan 14 13:44:15 2017    #再等待2秒,打印这1个

示例2: 用Daemon方法示例(设置t为守护线程,就是子线程,跟着主线程一起退出)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     for t in threads:
31         t.setDaemon(True) #设置t为守护线程; 注意:一定在start()之前设置,否则会报错
32
33         t.start()
34
35     print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 13:51:30 2017    #三个同时打印出来
2 Begin recording the python线程! Sat Jan 14 13:51:30 2017
3 all over Sat Jan 14 13:51:30 2017

示例3:设置t1为守护线程,没有意义,达不到效果,因为t2还会继续执行

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     t1.setDaemon(True)  #设置t1为守护线程; 注意:一定在start之前设置,否则会报错
31     for t in threads:
32
33         t.start()
34
35     print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 14:02:07 2017
2 Begin recording the python线程! Sat Jan 14 14:02:07 2017
3 all over Sat Jan 14 14:02:07 2017          #设置t1为守护线程,所以会先把这三条先打印出来
4
5 end listening Sat Jan 14 14:02:10 2017     #再等待3秒打印t2,
6
7 end recording Sat Jan 14 14:02:12 2017     #再等待3秒打印这条出来

示例4:设置t2为守护线程,子线程才会跟着主线程一起退出

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     t2.setDaemon(True)  # 设置t2为守护线程; 注意:一定在start之前设置,否则会报错
31     for t in threads:
32
33         t.start()
34
35     print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 14:17:09 2017
2 Begin recording the python线程! Sat Jan 14 14:17:09 2017
3 all over Sat Jan 14 14:17:09 2017       #先打印这三条
4
5 end listening Sat Jan 14 14:17:12 2017  #等待3秒,再打印这条;t1结束后,主线程也结束了。

2、一道面试题

 1 #执行结果是什么?2 3 i = 04 for i in range(10):5     i += 16 print(i)7 8 执行结果:9 10

3、其它方法

示例:getName()方法 (一般没什么用)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     t2.setDaemon(True)  # 设置t为守护进程; 注意:一定在start之前设置,否则会报错
31     for t in threads:
32         t.start()
33         print(t.getName())    #返回线程名称:Thread-1
34
35     print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 14:36:44 2017
2 Thread-1   #返回线程名称
3 Begin recording the python线程! Sat Jan 14 14:36:44 2017
4 Thread-2   #返回默认的线程名称
5 all over Sat Jan 14 14:36:44 2017
6 end listening Sat Jan 14 14:36:47 2017

示例:threading.activeCount(),返回正在运行的线程数量

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 from time import ctime,sleep
 7 import time
 8
 9 def ListenMusic(name):
10
11         print ("Begin listening to %s. %s" %(name,ctime()))
12         sleep(3)
13         print("end listening %s"%ctime())
14
15 def RecordBlog(title):
16
17         print ("Begin recording the %s! %s" %(title,ctime()))
18         sleep(5)
19         print('end recording %s'%ctime())
20
21 #创建一个列表,把t1和t2加到列表中去
22 threads = []
23 t1 = threading.Thread(target=ListenMusic,args=('水手',))
24 t2 = threading.Thread(target=RecordBlog,args=('python线程',))
25 threads.append(t1)
26 threads.append(t2)
27
28 if __name__ == '__main__':
29
30     t2.setDaemon(True)  #设置t为守护进程; 注意:一定在start之前设置,否则会报错
31     for t in threads:
32         t.start()
33
34         print("count:", threading.active_count())   #判断有多少个线程的数量
35
36     while threading.active_count()==1:  #等于1就相当于只有一个主线程,没有子线程
37
38         print ("all over %s" %ctime())

执行结果:

1 Begin listening to 水手. Sat Jan 14 14:49:00 2017
2 count: 2
3 Begin recording the python线程! Sat Jan 14 14:49:00 2017
4 count: 3  #得到的线程数量
5 end listening Sat Jan 14 14:49:03 2017

五、进程与线程的关系区别                                                                                                                                    

1、一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)
2、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
3、线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和 程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
4、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调 度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程 自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是 它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

六、python的GIL                                                                                                                                              

  In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once.This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features havegrownto depend on the guarantees that it enforces.)上面的核心意思就是:无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行。

常见概念:

1、什么是并发和并行?

并发:是指系统具有处理多个任务(动作)的能力(CPU通过切换来完成并发),并发是并行的一个子集。

并行:是指系统具有同时处理多个任务(动作)的能力

2、同步与异步的区别?

同步: 当进程执行到一个IO(等待外部数据)的时候你---->会一直等:同步 (示例: 打电话)

异步:当进程执行到一个IO(等待外部数据)的时候你---->不等:一直等到数据接收成功,再回来处理。异步效率更高(示例:发短信)

3、任务分为

1、对于IO密集型的任务:  python的多线程是有意义的,可以采用:多进程+协程的方式
2、对于计算密集型的任务:python的多线程就不推荐。python就不适用了。

七、同步锁                                                                                                                                                               

示例1:不加锁(拿到的值是不固定的)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 def sub():
 9     global num
10
11     # num -= 1
12     temp=num
13     time.sleep(0.001)   #别外75个线程,拿到100了,时间不固定。
14     num=temp-1
15
16 num =100
17
18 l=[]
19
20 for i in range(100):
21     t=threading.Thread(target=sub)
22     t.start()
23     l.append(t)
24
25 for t in l:
26     t.join()
27
28 print(num)

执行结果:

1 73 or 75  (这个值是随机的,会不断变化)

示例2:加锁 (加锁的作用:就是把多线程变成串行,结果不会变)

 1 #加锁的作用:就是把多线程变成串行,结果就不会变)
 2
 3 #!/usr/bin/env python
 4 # -*- coding:utf-8 -*-
 5 #Author: nulige
 6
 7 import threading
 8 import time
 9
10 def sub():
11
12     global num
13
14     # num -= 1
15     lock.acquire()  #获取锁
16     temp=num
17     time.sleep(0.001)
18     num=temp-1
19     lock.release()  #释放锁
20
21 num =100
22
23 l=[]
24 lock=threading.Lock()
25
26 for i in range(100):
27     t=threading.Thread(target=sub)
28     t.start()
29     l.append(t)
30
31 for t in l:
32     t.join()
33
34 print (num)

执行结果:

1 0

GIL:全局解释器锁
作用:保证同一时刻,只有一个线程被CPU执行,无论你有多少个线程。

为什么这里还需要lock? 注意啦,这里的lock是用户级的lock,跟那个GIL没关系 ,具体我们通过下图进行讲解

  既然用户程序已经自己有锁了,那为什么C python还需要GIL呢?加入GIL主要的原因是为了降低程序的开发的复杂度,比如现在的你写python不需要关心内存回收的问题,因为Python解释器帮你自动定期进行内存回收,你可以理解为python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数据是可以被清空的,此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量,py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了,结果就有可能新赋值的数据被删除了,为了解决类似的问题,python解释器简单粗暴的加了锁,即当一个线程运行时,其它人都不能动,这样就解决了上述的问题,这可以说是Python早期版本的遗留问题。

八、线程死锁和递归锁                                                                                                                                                 

  在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都

正在使用,所有这两个线程在无外力作用下将一直等待下去。

示例1:线程死锁

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author: nulige
 4
 5 import threading
 6 import time
 7
 8
 9 class MyThread(threading.Thread):
10     def actionA(self):
11         A.acquire()  # count=1
12         print(self.name, "gotA", time.ctime())
13         time.sleep(2)
14
15         B.acquire()  # count=2
16         print(self.name, "gotB", time.ctime())
17         time.sleep(1)
18
19         B.release()  # count=1
20         A.release()  # count=0
21
22     def actionB(self):
23         B.acquire()  # count=1
24         print(self.name, "gotB", time.ctime())
25         time.sleep(2)
26
27         A.acquire()  # count=2
28         print(self.name, "gotA", time.ctime())
29         time.sleep(1)
30
31         A.release()  # count=1
32         B.release()  # count=0
33
34     def run(self):
35         self.actionA()
36         self.actionB()
37
38
39 if __name__ == '__main__':
40
41     A = threading.Lock()
42     B = threading.Lock()
43
44     L = []
45
46     for i in range(5):
47         t = MyThread()
48         t.start()
49         L.append(t)
50
51     for i in L:
52         i.join()
53
54     print("ending.....")

执行结果:

1 Thread-1 gotA Mon Jan 16 17:33:58 2017
2 Thread-1 gotB Mon Jan 16 17:34:00 2017
3 Thread-1 gotB Mon Jan 16 17:34:01 2017
4 Thread-2 gotA Mon Jan 16 17:34:01 2017  #死锁,一直卡在这里

解决办法:

使用递归锁,将

1
2
lockA=threading.Lock()
lockB=threading.Lock()<br>#--------------<br>lock=threading.RLock()

为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

示例2:递归锁(解决死锁问题)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading
 6 import time
 7
 8 class MyThread(threading.Thread):
 9
10     def actionA(self):
11
12         r_lcok.acquire()  #count=1
13         print(self.name,"gotA",time.ctime())
14         time.sleep(2)
15
16         r_lcok.acquire()  #count=2
17         print(self.name,"gotB",time.ctime())
18         time.sleep(1)
19
20         r_lcok.release()  #count=1
21         r_lcok.release()  #count=0
22
23
24     def actionB(self):
25
26         r_lcok.acquire()  #count=1
27         print(self.name,"gotB",time.ctime())
28         time.sleep(2)
29
30         r_lcok.acquire()  #count=2
31         print(self.name,"gotA",time.ctime())
32         time.sleep(1)
33
34         r_lcok.release()  #count=1
35         r_lcok.release()  #count=0
36
37     def run(self):
38
39             self.actionA()
40             self.actionB()
41
42 if __name__ == '__main__':
43
44     r_lcok=threading.RLock()
45     L=[]
46
47     for i in range(5):
48         t=MyThread()
49         t.start()
50         L.append(t)
51
52     for i in L:
53         i.join()
54
55     print("ending.....")

执行结果:

 1 Thread-1 gotA Mon Jan 16 17:38:42 2017
 2 Thread-1 gotB Mon Jan 16 17:38:44 2017
 3 Thread-1 gotB Mon Jan 16 17:38:45 2017
 4 Thread-1 gotA Mon Jan 16 17:38:47 2017
 5 Thread-3 gotA Mon Jan 16 17:38:48 2017
 6 Thread-3 gotB Mon Jan 16 17:38:50 2017
 7 Thread-4 gotA Mon Jan 16 17:38:51 2017
 8 Thread-4 gotB Mon Jan 16 17:38:53 2017
 9 Thread-5 gotA Mon Jan 16 17:38:54 2017
10 Thread-5 gotB Mon Jan 16 17:38:56 2017
11 Thread-5 gotB Mon Jan 16 17:38:57 2017
12 Thread-5 gotA Mon Jan 16 17:38:59 2017
13 Thread-3 gotB Mon Jan 16 17:39:00 2017
14 Thread-3 gotA Mon Jan 16 17:39:02 2017
15 Thread-4 gotB Mon Jan 16 17:39:03 2017
16 Thread-4 gotA Mon Jan 16 17:39:05 2017
17 Thread-2 gotA Mon Jan 16 17:39:06 2017
18 Thread-2 gotB Mon Jan 16 17:39:08 2017
19 Thread-2 gotB Mon Jan 16 17:39:09 2017
20 Thread-2 gotA Mon Jan 16 17:39:11 2017
21 ending.....

View Code

九、同步条件(Event)                                                                                                                                        

An event is a simple synchronization object;the event represents an internal flag,
and threads can wait for the flag to be set, or set or clear the flag themselves.
event = threading.Event()# a client thread can wait for the flag to be set
event.wait()# a server thread can set or reset it
event.set()
event.clear()If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.

示例:

 1 import threading,time
 2 class Boss(threading.Thread):
 3     def run(self):
 4         print("BOSS:今晚大家都要加班到22:00。")
 5         print(event.isSet())
 6         event.set()
 7         time.sleep(5)
 8         print("BOSS:<22:00>可以下班了。")
 9         print(event.isSet())
10         event.set()
11 class Worker(threading.Thread):
12     def run(self):
13         event.wait()
14         print("Worker:哎……命苦啊!")
15         time.sleep(1)
16         event.clear()
17         event.wait()
18         print("Worker:OhYeah!")
19 if __name__=="__main__":
20     event=threading.Event()
21     threads=[]
22     for i in range(5):
23         threads.append(Worker())
24     threads.append(Boss())
25     for t in threads:
26         t.start()
27     for t in threads:
28         t.join()

执行结果:

 1 BOSS:今晚大家都要加班到22:00。
 2 False
 3 Worker:哎……命苦啊!
 4 Worker:哎……命苦啊!
 5 Worker:哎……命苦啊!
 6 Worker:哎……命苦啊!
 7 Worker:哎……命苦啊!
 8 BOSS:<22:00>可以下班了。
 9 False
10 Worker:OhYeah!
11 Worker:OhYeah!
12 Worker:OhYeah!
13 Worker:OhYeah!
14 Worker:OhYeah!
15 ending.....

View Code

十、信号量(Semaphore)

信号量:指同时开几个线程并发

  信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。

计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

   BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import threading,time
 6
 7 class myThread(threading.Thread):
 8     def run(self):           #启动后,执行run方法
 9         if semaphore.acquire():  #加把锁,可以放进去多个(相当于5把锁,5个钥匙,同时有5个线程)
10             print(self.name)
11             time.sleep(5)
12             semaphore.release()
13
14 if __name__=="__main__":
15     semaphore=threading.Semaphore(5)  #同时能有几个线程进去(设置为5就是一次5个线程进去),类似于停车厂一次能停几辆车
16
17     thrs=[] #空列表
18     for i in range(100): #100个线程
19         thrs.append(myThread()) #加线程对象
20
21     for t in thrs:
22         t.start()  #分别启动

执行结果:

 1 Thread-1
 2 Thread-2
 3 Thread-3
 4 Thread-4
 5 Thread-5   #5个线程同时出来
 6
 7 Thread-8
 8 Thread-6
 9 Thread-9
10 Thread-7
11 Thread-10  #每隔3秒再打印5个出来
12
13 部分省略.......

十一、多线程利器---队列(queue)    ( 重点掌握)                                                                                             

列表是不安全的数据结构

示例:

 1 #两个线程同时删除5,所以会报错,因为只有一个5,一个线程删除了就没有啦。
 2
 3 import threading,time
 4
 5 li=[1,2,3,4,5]
 6
 7 def pri():
 8     while li:
 9         a=li[-1]  #取值
10         print(a)
11         time.sleep(1)
12         li.remove(a)  #remove按索引去删除内容
13
14 t1=threading.Thread(target=pri,args=())  #线程1
15 t1.start()
16 t2=threading.Thread(target=pri,args=())  #线程2
17 t2.start()

执行结果:

 1 #会报错,因为只有一个5,删除了就没有啦,不能两个线程同时删除。
 2
 3 5
 4 5
 5 4
 6 Exception in thread Thread-2:
 7 Traceback (most recent call last):
 8   File "C:\Python3.5\lib\threading.py", line 914, in _bootstrap_inner
 9     self.run()
10   File "C:\Python3.5\lib\threading.py", line 862, in run
11     self._target(*self._args, **self._kwargs)
12   File "D:/python/day34/s10.py", line 34, in pri
13     li.remove(a)
14 ValueError: list.remove(x): x not in list
15
16 3
17 2
18 1

View Code

思考:如何通过对列来完成上述功能?

queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.

queue列队的三种模式及构造函数

1、先进先出模式 (谁先进去,谁先出来)   ---->class queue.Queue(maxsize)

2、先进后出模式  (先进去的,最后出来)  ---->class queue.LifoQueue(maxsize)

3、优先级模式    (优先级越低,先出来)   ---->class queue.PriorityQueue(maxsize)

一、先进先出

示例1:

 1 #先进先出 (原则:谁先进去,谁就先出来)
 2 import queue  #线程 队列
 3
 4 q=queue.Queue() #先进先出
 5 q.put(12)
 6 q.put("hello")
 7 q.put({"name":"yuan"})
 8
 9 while 1:
10     data=q.get()
11     print(data)
12     print("-----------")

执行结果:

1 12            #他是第1个进去的,所以他先出来
2 -----------
3 hello
4 -----------
5 {'name': 'yuan'}
6 -----------

示例2:

 1 import queue  #队列,解决多线程问题  (注意:python2.7 Queue的首字母是大写的)
 2
 3
 4 # q=queue.Queue(3) #1、设置3就是满了,默认(FIFO 先进先出 ) #先进后出(手枪弹夹,后压进去的,先出来)
 5 q=queue.Queue()
 6 q.put(12)
 7 q.put("hello")
 8 q.put({"name":"yuan"})
 9
10 q.put(34)
11 # q.put(34,False) #2、blook=True,如果改成Flase,提示你满了,会报错,但不会卡在这里
12
13
14 while 1:
15     data=q.get()  #1、会卡着,等值进来
16     # data=q.get(block=False)  #3、队列为空
17     print(data)
18     print("-----------")

二、先进后出

示例:

 1 #先进后出
 2 import queue
 3
 4 q=queue.LifoQueue()  #先进后出
 5
 6 q.put(12)
 7 q.put("hello")
 8 q.put({"name":"yuan"})
 9
10 while 1:
11     data=q.get()  #卡着,等值进来,
12     print(data)
13     print("-----------")

执行结果:

1 {'name': 'yuan'}  #后进来的先出去
2 -----------
3 hello
4 -----------
5 12
6 -----------

三、优化级

示例:

 1 #优先级
 2 import queue
 3
 4 q=queue.PriorityQueue()  #优先级
 5
 6 q.put([3,12])
 7 q.put([2,"hello"])  #2先出来,按优化级  级别是:2--->3--->4 从级到高
 8 q.put([4,{"name":"yuan"}])
 9
10 while 1:
11     data=q.get()
12     print(data[1])
13     print("-----------------------")

执行结果:

1 hello                 #2先出来,按优先级
2 -----------------------
3 12
4 -----------------------
5 {'name': 'yuan'}
6 -----------------------

queue队列类的方法:

创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,
get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。此包中的常用方法(q = Queue.Queue()):q.qsize()  返回队列的大小
q.empty()  如果队列为空,返回True,反之False
q.full()   如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]])  获取队列,timeout等待时间
q.get_nowait()      相当q.get(False)
非阻塞 q.put(item)   写入队列,timeout等待时间
q.put_nowait(item)  相当q.put(item, False)
q.task_done()  在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join()       实际上意味着等到队列为空,再执行别的操作

示例1: q.qsize() and q.empty() and q.full

 1 import queue
 2
 3 q=queue.Queue()
 4 q.put(12)
 5 q.put("hello")
 6 q.put({"name":"yuan"})
 7
 8 print(q.qsize()) #判断队列大小
 9 print(q.empty()) #判断队列是否为空
10 print(q.full)    #判断队列是否满了
11
12 while 1:
13     data=q.get()
14     print(data)
15     print("-----------")

执行结果:

3 --->q.qsize()False ---->q.empty()<bound method Queue.full of <queue.Queue object at 0x01315A70>> --->full

示例2:g.put_nowait() 相当于q.get(Flase)

 1 import queue
 2
 3 q=queue.Queue(3)
 4
 5 q.put(12)
 6 q.put([2,"hello"])
 7 q.put([4,{"name":"yuan"}])
 8
 9 q.put_nowait(56)  #相当于q.get(Flase)
10
11 while 1:
12     data=q.get()
13     print(data)

执行结果:

1 Traceback (most recent call last):
2   File "D:/python/day34/s7.py", line 79, in <module>
3     q.put_nowait(56)  #相当于q.get(Flase)
4   File "C:\Python3.5\lib\queue.py", line 184, in put_nowait
5     return self.put(item, block=False)
6   File "C:\Python3.5\lib\queue.py", line 130, in put
7     raise Full
8 queue.Full

十二、生产者消费者模型                                                                                                            

  1、为什么要使用生产者和消费者模式

  在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

  2、什么是生产者消费者模式

  生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。

示例1:边做包子,边吃包子

 1 #生产者消费者模型(生产者先执行,再吃包子。)
 2
 3 import time,random
 4 import queue,threading
 5
 6 q = queue.Queue()
 7
 8 def Producer(name):
 9   count = 0
10   while count <10:
11     print("making........")
12     time.sleep(random.randrange(3)) #产生一个随机数(1-2秒之间)
13     q.put(count)
14     print('Producer %s has produced %s baozi..' %(name, count))
15     count +=1
16     print("ok......")
17
18 def Consumer(name):
19   count = 0
20   while count <10:
21     time.sleep(random.randrange(4))  #产生一个随机数(1-3秒之间)
22     if not q.empty():
23         data = q.get()
24         print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
25     else:
26         print("-----no baozi anymore----")
27         count +=1
28
29 p1 = threading.Thread(target=Producer, args=('A君',))
30 c1 = threading.Thread(target=Consumer, args=('B君',))
31
32 p1.start()
33 c1.start()

执行结果:

 1 making........
 2 Producer A君 has produced 0 baozi..
 3 ok......
 4 making........
 5 Consumer B君 has eat 0 baozi...
 6 Producer A君 has produced 1 baozi..
 7 ok......
 8 making........
 9 Consumer B君 has eat 1 baozi...
10 Producer A君 has produced 2 baozi..
11 ok......
12 making........
13 Consumer B君 has eat 2 baozi...
14 Producer A君 has produced 3 baozi..
15 ok......
16 making........
17 Producer A君 has produced 4 baozi..
18 ok......
19 making........
20 Consumer B君 has eat 3 baozi...
21 Producer A君 has produced 5 baozi..
22 ok......
23 making........
24 Producer A君 has produced 6 baozi..
25 ok......
26 making........
27 Consumer B君 has eat 4 baozi...
28 Producer A君 has produced 7 baozi..
29 ok......
30 making........
31 Producer A君 has produced 8 baozi..
32 ok......
33 making........
34 Producer A君 has produced 9 baozi..
35 ok......
36 Consumer B君 has eat 5 baozi...
37 Consumer B君 has eat 6 baozi...
38 Consumer B君 has eat 7 baozi...
39 Consumer B君 has eat 8 baozi...
40 Consumer B君 has eat 9 baozi...
41 -----no baozi anymore----
42 -----no baozi anymore----
43 -----no baozi anymore----
44 -----no baozi anymore----
45 -----no baozi anymore----
46 -----no baozi anymore----
47 -----no baozi anymore----
48 -----no baozi anymore----
49 -----no baozi anymore----
50 -----no baozi anymore----

View Code

示例2: 供不应求,吃包子的人太多了(1个人在生产包子,3个人在吃包子)

 1 #生产者消费者模型(供不应求,吃的人太多了,生产不赢)
 2
 3 import time,random
 4 import queue,threading
 5
 6 q = queue.Queue()
 7
 8 def Producer(name):
 9   count = 0
10   while count <10:
11     print("making........")
12     time.sleep(random.randrange(3)) #产生一个随机数(1-2秒之间)
13     q.put(count)
14     print('Producer %s has produced %s baozi..' %(name, count))
15     count +=1
16     print("ok......")
17
18 def Consumer(name):
19   count = 0
20   while count <10:
21     time.sleep(random.randrange(4))  #产生一个随机数(1-3秒之间)
22     if not q.empty():
23         data = q.get()
24         print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
25     else:
26         print("-----no baozi anymore----")
27         count +=1
28
29 p1 = threading.Thread(target=Producer, args=('A君',))  #1个人生产包子
30 c1 = threading.Thread(target=Consumer, args=('B君',))
31 c2 = threading.Thread(target=Consumer, args=('C君',))  #3个人在吃包子,导致吃包子的人太多啦,生产不赢
32 c3 = threading.Thread(target=Consumer, args=('D君',))
33
34 p1.start()
35 c1.start()
36 c2.start()
37 c3.start()

执行结果:

 1 making........
 2 -----no baozi anymore----      #生产不赢,供不应求,吃包子的人太多了
 3 -----no baozi anymore----
 4 Producer A君 has produced 0 baozi..
 5 ok......
 6 making........
 7 Producer A君 has produced 1 baozi..
 8 ok......
 9 making........
10 Consumer C君 has eat 0 baozi...
11 Consumer D君 has eat 1 baozi...
12 -----no baozi anymore----
13 -----no baozi anymore----
14 -----no baozi anymore----
15 -----no baozi anymore----
16 -----no baozi anymore----
17 -----no baozi anymore----
18 Producer A君 has produced 2 baozi..
19 ok......
20 making........
21 Producer A君 has produced 3 baozi..
22 ok......
23 making........
24 Producer A君 has produced 4 baozi..
25 ok......
26 making........
27 Consumer C君 has eat 2 baozi...
28 Consumer D君 has eat 3 baozi...
29 Consumer D君 has eat 4 baozi...
30 -----no baozi anymore----
31 -----no baozi anymore----
32 Producer A君 has produced 5 baozi..
33 ok......
34 making........
35 Producer A君 has produced 6 baozi..
36 ok......
37 making........
38 Producer A君 has produced 7 baozi..
39 ok......
40 making........
41 Producer A君 has produced 8 baozi..
42 ok......
43 making........
44 Consumer B君 has eat 5 baozi...
45 Consumer C君 has eat 6 baozi...
46 Consumer D君 has eat 7 baozi...
47 Producer A君 has produced 9 baozi..
48 ok......
49 Consumer B君 has eat 8 baozi...
50 Consumer C君 has eat 9 baozi...
51 -----no baozi anymore----
52 -----no baozi anymore----
53 -----no baozi anymore----
54 -----no baozi anymore----
55 -----no baozi anymore----
56 -----no baozi anymore----
57 -----no baozi anymore----
58 -----no baozi anymore----
59 -----no baozi anymore----
60 -----no baozi anymore----
61 -----no baozi anymore----
62 -----no baozi anymore----
63 -----no baozi anymore----
64 -----no baozi anymore----
65 -----no baozi anymore----
66 -----no baozi anymore----
67 -----no baozi anymore----
68 -----no baozi anymore----
69 -----no baozi anymore----
70 -----no baozi anymore----

View Code

示例3:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import time,random
 6 import queue,threading
 7
 8 q = queue.Queue()
 9
10 def Producer(name):
11   count = 0
12   while count <10:
13     print("making........")
14     time.sleep(5)
15     q.put(count)
16     print('Producer %s has produced %s baozi..' %(name, count))
17     count +=1
18     q.task_done()  #发信号告诉队列在生产包子,让join接收,就开始吃包子
19     print("ok......")
20
21 def Consumer(name):
22   count = 0
23   while count <10:
24         time.sleep(random.randrange(4))  #产生一个随机数(1秒-3秒之间)
25         print("waiting...等待包子做的过程中...")
26         q.join()  #join开始接收
27         data = q.get()
28         print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
29         count +=1
30
31 p1 = threading.Thread(target=Producer, args=('A君',))
32 c1 = threading.Thread(target=Consumer, args=('B君',))
33 c2 = threading.Thread(target=Consumer, args=('C君',))
34 c3 = threading.Thread(target=Consumer, args=('D君',))
35
36 p1.start()
37 c1.start()
38 c2.start()
39 c3.start()

执行结果:

 1 making........
 2 waiting...等待包子做的过程中...
 3 waiting...等待包子做的过程中...
 4 waiting...等待包子做的过程中...
 5 Producer A君 has produced 0 baozi..
 6 ok......
 7 making........
 8 Consumer D君 has eat 0 baozi...
 9 waiting...等待包子做的过程中...
10 Producer A君 has produced 1 baozi..
11 Consumer B君 has eat 1 baozi...
12 waiting...等待包子做的过程中...
13 ok......
14 making........
15 部分代码省略......

View Code

示例4:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 import time,random
 6 import queue,threading
 7
 8 q = queue.Queue()
 9
10 def Producer(name):
11   count = 0
12   while count <10:
13     print("making.....正在制作包子...")
14     time.sleep(5)
15     q.put(count)
16     print('Producer %s has produced %s baozi..' %(name, count))
17     count +=1
18     q.join()
19     print("ok......")
20
21 def Consumer(name):
22   count = 0
23   while count <10:
24         time.sleep(random.randrange(4))  #产生一个随机数(1秒-3秒之间)
25         data = q.get()
26         print("eating.......")
27         time.sleep(4)  #4秒钟这后
28         q.task_done()  #给他发一个信号,才打印ok
29         print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
30         count +=1
31
32 p1 = threading.Thread(target=Producer, args=('A君',))
33 c1 = threading.Thread(target=Consumer, args=('B君',))
34 c2 = threading.Thread(target=Consumer, args=('C君',))
35 c3 = threading.Thread(target=Consumer, args=('D君',))
36
37 p1.start()
38 c1.start()
39 c2.start()
40 c3.start()

执行结果:

 1 making.....正在制作包子...
 2 Producer A君 has produced 0 baozi..
 3 eating.......
 4 Consumer B君 has eat 0 baozi...
 5 ok......
 6 making.....正在制作包子...
 7 Producer A君 has produced 1 baozi..
 8 eating.......
 9 Consumer C君 has eat 1 baozi...
10 ok......
11 making.....正在制作包子...
12 Producer A君 has produced 2 baozi..
13 eating.......
14 Consumer D君 has eat 2 baozi...
15 ok......
16 making.....正在制作包子...
17 Producer A君 has produced 3 baozi..
18 eating.......
19 Consumer B君 has eat 3 baozi...
20 ok......
21 making.....正在制作包子...
22 Producer A君 has produced 4 baozi..
23 eating.......
24 Consumer C君 has eat 4 baozi...
25 ok......
26 making.....正在制作包子...
27 Producer A君 has produced 5 baozi..
28 eating.......
29 Consumer D君 has eat 5 baozi...
30 ok......
31 making.....正在制作包子...
32 Producer A君 has produced 6 baozi..
33 eating.......
34 Consumer B君 has eat 6 baozi...
35 ok......
36 making.....正在制作包子...

View Code

总结:

task_done和join必须成对出现,类似于一个通信工具,我给你发个信号,你就知道我做了某个操作

(例如:put or get) 对方就是join。如果我put or get 你就处理。(类似于收到信号就处理)

类似于,我发信号,你收到就处理,没收到就Join卡住,一直在那等待。

十三、多进程模块 multiprocessing (主要解决GIL问题)                                

Multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency,effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。

multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情景。

一、进程的调用

调用方式1:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 #Author: nulige
 4
 5 #多进程调用(并行)
 6
 7 from multiprocessing import Process
 8 import time
 9
10
11 def f(name):
12     time.sleep(1)
13     print('hello', name,time.ctime())
14
15 if __name__ == '__main__':
16     p_list=[]
17     for i in range(3):  #子进程
18
19         p = Process(target=f, args=('alvin',))
20         p_list.append(p)
21         p.start()
22
23     for i in p_list:
24         i.join()
25
26     print('end')  #主进程

执行结果:

1 hello alvin Mon Jan 16 18:38:08 2017  #并行,三个同时出现
2 hello alvin Mon Jan 16 18:38:08 2017
3 hello alvin Mon Jan 16 18:38:08 2017
4 end

调用方式2:

示例1: 1秒钟这后,4条消息同时执行

 1 from multiprocessing import Process
 2 import time
 3
 4 class MyProcess(Process):
 5
 6     def run(self):
 7         time.sleep(1)
 8         print ('hello', self.name,time.ctime())
 9
10
11 if __name__ == '__main__':
12     p_list=[]
13     for i in range(3):
14         p = MyProcess()  #进程对象
15         p.start()        #启动执行run方法
16         p_list.append(p)
17
18     for p in p_list:
19         p.join()  #子进程没有执行完,主进程会一直等待
20
21     print('end')

执行结果:

1 hello MyProcess-1 Mon Jan 16 18:56:58 2017  #结果同时出来
2 hello MyProcess-2 Mon Jan 16 18:56:58 2017
3 hello MyProcess-3 Mon Jan 16 18:56:58 2017
4 end

示例2:daemon=True 是属性,不是方法

 1 #设置为守护进程,打印的就是end
 2
 3 from multiprocessing import Process
 4 import time
 5
 6 class MyProcess(Process):
 7
 8     def run(self):
 9         time.sleep(1)
10         print ('hello', self.name,time.ctime())
11
12 if __name__ == '__main__':
13     p_list=[]
14
15     for i in range(3):
16         p = MyProcess()  #进程对象
17         p.daemon=True  #是属性,不是方法
18         p.start()       #启动执行sun方法
19         p_list.append(p)
20
21     print('end')   #主进程执行完之后,不管守护进程

执行结果:

1 end

调用方法3:

 1 from multiprocessing import Process
 2 import os
 3 import time
 4
 5 def info(title):
 6     print("title:", title)
 7     print('parent process:', os.getppid())  #父进程的pid
 8     print('process id:', os.getpid())       #打印进程号9
10 def f(name):
11     info('function f')
12     print('hello', name)
13
14 if __name__ == '__main__':
15     info('main process line')
16
17     time.sleep(1)
18     print("------------------")
19     p = Process(target=info, args=('yuan',))
20     p.start()
21     p.join()

执行结果:

1 title: main process line
2 parent process: 4204
3 process id: 7280
4 ------------------
5 title: yuan
6 parent process: 7280
7 process id: 3596

转载于:https://www.cnblogs.com/xyt521/p/6291989.html

Python之进程线程相关推荐

  1. Python之进程+线程+协程(异步、selectors模块、阻塞、非阻塞IO)

    文章目录 一.IO多路复用 二.selectors模块 本篇文字是关于IO多路复用的更深入一步的总结,上一篇 Python之进程+线程+协程(事件驱动模型.IO多路复用.select与epoll)对I ...

  2. python的进程线程和协程_python成长之路 :线程、进程和协程

    python线程 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分 ...

  3. Python之进程+线程+协程(multiprocessing多进程模块)

    前几篇的多线程模块的各种规则和用法,本篇则是关于多进程模块的内容 1.multiprocessing的介绍 在Python中,由于有GIL解释器锁的存在,多线程就根本不是本质意义上的多线程,而是一个主 ...

  4. Python之进程+线程+协程(同步对象、信号量、队列)

    文章目录 Event同步对象 semaphore信号量 队列 本篇是关于Python进程方面的内容了,主要是Event同步对象,信号量和队列 Event同步对象 1.概念: 我们可以对一个线程set一 ...

  5. Python之进程+线程+协程(并发与并行、GIL锁、同步锁、死锁、递归锁)

    文章目录 一.并发与并行 二.同步与异步 三.线程锁 1.GIL全局解释器锁 2.同步锁 3.死锁 4.递归锁 在Python中GIL解释器锁.同步锁.死锁.递归锁都是什么?怎么这么多锁,它们都是用来 ...

  6. Python之进程+线程+协程(进程的本质 与 threading线程模块)

    文章目录 基本概念 threading线程模块 本篇开始分析Python中的并发程序,也就是进程.线程.协程序的使用.由于是用自己的语言总结的,因此比较大白话,或者叫通俗易懂.而且很多细节方面没有具体 ...

  7. Python之进程+线程+协程(事件驱动模型、IO多路复用、select与epoll)

    文章目录 一.事件驱动模型 二.IO多路复用 本篇文章是关于涉及网络编程与协程.进程之间结合的内容,其中事件驱动模型.IO多路复用.select与epoll的使用等方面的知识 一.事件驱动模型 1.事 ...

  8. Python之进程+线程+协程(进程间通信、进程同步、进程池、回调函数)

    文章目录 进程间通信 进程同步 进程池 回调函数 本篇文章依然是进程.线程方面的内容,主要讲进程间的通信.进程队列.进程同步.进程池.进程同步和回调函数 进程间通信 进程就是两个独立的内存空间在运行, ...

  9. Python之进程+线程+协程(生产者消费者模型)

    本篇主要总结一下非常有名的生成者消费者模型 概念引用 1.为什么要使用生产者和消费者模型? 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快, ...

最新文章

  1. 高并发场景下的限流策略
  2. Android发展Singleton模式
  3. ML之NB:利用朴素贝叶斯NB算法(TfidfVectorizer+不去除停用词)对20类新闻文本数据集进行分类预测、评估
  4. CentOS ASP.NET Core Runtime Jexus跨平台布署
  5. voxelnet_ue4商城资源Voxel Sandbox Toolkit体素沙盒工具箱
  6. 计划的主体部分应有哪些内容_本科论文查重查哪些部分内容?需要注意什么?...
  7. shell 做加法运算_使用shell脚本实现加法乘法运算
  8. 今天的几经沧桑的飞鸽传书2011
  9. 2007标注没有文字_Hi,siri,你的商标注册了吗
  10. 如何用新安装的jdk替换掉Linux系统默认jdk
  11. 02.环境准备-idea配置maven
  12. ubuntu下载安装nginx+nginx-rtmp-module
  13. MATLAB语音识别系统[声纹识别]
  14. 打开IIS管理器的两种方式
  15. python调用讯飞付费版语音转写
  16. 学习笔记 --- DM9000网卡原理与基地址设置
  17. 最简单的 QQ分享、微信分享、一键加QQ群 引入
  18. 用PS绘制立体字的效果教程
  19. 工业农业消防自动检测及报警云方案
  20. CF140C New Year Snowmen(贪心+优先队列)

热门文章

  1. 微信小程序 view文字水平垂直居中
  2. CSS — 让网页美起来(二)
  3. Prometheus容器化部署,配合Grafan画图工具监控节点信息
  4. 信息传输率(Information Translate Rate,ITR)
  5. app功能测试知识汇总
  6. 网络攻击是如何运作的—一份完整的列表 ( 2 )
  7. 开封微信朋友圈广告是如何投放的?
  8. 电子采购流程全解析!看这一篇就够了
  9. 淘宝、1688代购系统;微信代购小程序,代购系统源代码,PHP前端源码演示
  10. element ui table左侧选中,右侧渲染,右侧删除单个标签,左侧对应标签不选中