线程、进程和协程

1、python 线程

Threading 用于提供线程相关的操作,线程是应用程序中工作最小的单元。

 1 #-*-coding:utf-8-*-
 2 #!/usr/bin/env python
 3 __author__ = 'bravexz'
 4 
 5 import threading
 6 import time
 7 
 8 def show(arg):
 9     time.sleep(1)
10     print "thread"+str(arg)
11 
12 for i in range(10):
13     t = threading.Thread(target=show,args=(i,))
14     t.start()
15 
16 print "main thread stop"

上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行命令。

  • start            线程准备就绪,等待CPU调度
  • setName      为线程设置名称
  • getName      获取线程名称
  • setDaemon   设置为后台线程或前台线程(默认)
                       如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                        如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
  • join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
  • run              线程被cpu调度后执行Thread类对象的run方法

2、线程锁

由于线程之间是进行随机调度,并且每个线程可能只执行n条指令之后,CPU接着执行其他线程,所以可能出现如下问题:

 1 import time
 2 import threading
 3 
 4 g1_num = 0
 5 def show(arg):
 6     global g1_num
 7     time.sleep(1)
 8     g1_num +=1
 9     print g1_num
10 
11 for i in range(10):
12     t = threading.Thread(target=show,args=(i,))
13     t.start()
14 print "main thread stop"

为了解决上面的问题,我们加入了线程锁机制,能够很好的解决以上问题了。

 1 import threading
 2 import time
 3 
 4 g1_num = 0
 5 lock = threading.RLock()
 6 def Func():
 7     lock.acquire()
 8     global g1_num
 9     g1_num +=1
10     time.sleep(1)
11     print g1_num
12     lock.release()
13 
14 for i in range(10):
15     t = threading.Thread(target=Func)
16     t.start()

3、event

python 线程的事件用于主线程控制其他线程的执行,事件主要提供了三种方法:set、wait、clear。

事件处理的机制:全文定义一个“Flag”,如果“Flag”值为False,那么当程序执行 event.wait方法时就会阻塞,如果“Flag”值为True,那么event.wait方法时便不再阻塞。

  • clear:将“Flag”设置为False
  • set:将“Flag”设置为True
 1 import threading
 2 
 3 def do(event):
 4     print "start"
 5     event.wait()
 6     print "execute"
 7 
 8 event_obj = threading.Event()
 9 for i in range(10):
10     t = threading.Thread(target=do,args=(event_obj,))
11     t.start()
12 
13 event_obj.clear()
14 inp = raw_input("input:")
15 if inp == "true":
16     event_obj.set()

 

4、python 进程

 1 from multiprocessing import Process
 2 import threading
 3 import time
 4 
 5 def foo(i):
 6     print "say hi",i
 7 
 8 for i in range(10):
 9     p = Process(target=foo,args=(i,))
10     p.start()

输入结果:

say hi 0
say hi 1
say hi 4
say hi 3
say hi 5
say hi 7
say hi 9
say hi 2
say hi 8
say hi 6

注明:以上代码必须在linux才可以正常运行。

4.1 进程数据共享

进程各自持有一份数据,默认无法共享数据

 1 from multiprocessing import Process
 2 from multiprocessing import Manager
 3 import time
 4 
 5 li = []
 6 def foo(i):
 7     li.append(i)
 8     print "say,hi",li
 9 
10 if __name__ == "__main__":
11     for i in range(10):
12         p = Process(target=foo,args=(i,))
13         p.start()
14 print "ending",li

输出结果:

ending []
ending []
say,hi [3]
ending []
say,hi [6]
ending []
say,hi [2]
ending []
say,hi [7]
ending []
say,hi [0]
ending []
say,hi [4]
ending []
say,hi [8]
ending []
say,hi [1]
ending []
say,hi [9]
ending []
say,hi [5]

如果解决这个问题呢,看下图:

 1 from multiprocessing import Process,Array
 2 temp = Array("i",[11,22,33,44])
 3 
 4 def Foo(i):
 5     temp[i] = 100+i
 6     for item in temp:
 7         print i,"------>",item
 8 
 9 if __name__ == "__main__":
10     for i in range(2):
11         p = Process(target=Foo,args=(i,))
12         p.start()

输出结果:

0 ------> 100
0 ------> 22
0 ------> 33
0 ------> 44
1 ------> 11
1 ------> 101
1 ------> 33
1 ------> 44

 1 from multiprocessing import Process,Manager
 2 manage = Manager()
 3 dic = manage.dict()
 4 def Foo(i):
 5     dic[i] = 100+i
 6     print dic.values()
 7 for i in range(2):
 8     p = Process(target=Foo,args=(i,))
 9     p.start()
10     p.join()

输出结果:

[root@centos6 lab]# python oldboy10.1.py
[100]
[100, 101]

当创建进程时(非使用时),共享数据会被拿到子进程中,当进程执行完毕后,再赋值给原值。

一下为进程锁实例:

 1 from multiprocessing import Process, Array, RLock
 2 
 3 def Foo(lock,temp,i):
 4     lock.acquire()
 5     temp[0] = 100+i
 6     for item in temp:
 7         print i,'----->',item
 8     lock.release()
 9 
10 lock = RLock()
11 temp = Array('i', [11, 22, 33, 44])
12 
13 for i in range(5):
14     p = Process(target=Foo,args=(lock,temp,i,))
15     p.start()
执行、运行结果:

[root@centos6 lab]# python oldboy10.2.py
0 -----> 100
0 -----> 22
0 -----> 33
0 -----> 44
2 -----> 102
2 -----> 22
2 -----> 33
2 -----> 44
3 -----> 103
3 -----> 22
3 -----> 33
3 -----> 44
4 -----> 104
4 -----> 22
4 -----> 33
4 -----> 44
1 -----> 101
1 -----> 22
1 -----> 33
1 -----> 44
[root@centos6 lab]#

 

4.2、进程池

进程池内部维护一个进程序列,当使用时,去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

  • apply
  • apply_async
 1 from multiprocessing import Process,Pool
 2 import time
 3 
 4 def Foo(i):
 5     time.sleep(2)
 6     return i+100
 7 def Bar(arg):
 8     print arg
 9 pool = Pool(5)
10 
11 for i in range(10):
12     pool.apply_async(func=Foo,args=(i,),callback= Bar)
13 print "end"
14 pool.close()
15 pool.join()
输出结果如下:

[root@centos6 lab]# python oldboy10.3.py
end
100
102
104
103
101
106
109
108
107
105
[root@centos6 lab]#

 

 5、协程

线程与进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

协程存在的意义:用于多线程的应用,CPU通过切片的方式来切换线程间的执行,而线程切换时需要耗时(保存状态,下次继续)。协程则只使用一个线程,在一个线程中规定某个代码块执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(I/O),适用于协程。

 

posted @ 2016-01-09 11:04  星空下的夜  阅读(170)  评论(0编辑  收藏  举报