Python读书笔记(四)---多线程编程

python提供了多个模块来支持多线程编程。

1._thread模块(python2中为thread)

_thread.start_new_thread(functionargs[, kwargs]):

启动一个新线程,并返回它的标识符。function代表函数名,args是一个tuple型的参数,若为空就是()。函数返回后,线程就自动退出。

 

_thread.allocate_lock():

返回一个lock object

 

lock.acquire(waitflag=1timeout=-1):

lock成功取到则返回True,否则返回false。

 

lock.release()

释放锁资源

 

lock.locked():

返回锁的状态,True代表被acquire成功。

有了上述几个函数,就可以通过实例来测试了

 1 from time import sleep, ctime
 2 import _thread
 3 
 4 loops = [4,2]
 5 
 6 def loop(nloop, nsec, lock):
 7     print('start loop0', nloop, 'at:',ctime())
 8     sleep(nsec)
 9     print('loop', nloop, 'done at:', ctime())
10     lock.release()
11     
12 def main():
13     print('starting at:', ctime())
14     locks = []
15     nloops = range(len(loops))
16     
17     for i in nloops:
18         lock = _thread.allocate_lock()
19         lock.acquire()
20         locks.append(lock)
21         
22     for i in nloops:
23         _thread.start_new_thread(loop, (i, loops[i], locks[i]))
24         
25     for i in nloops:
26         while locks[i].locked():
27             pass
28             
29     print('all Done at:', ctime())
30     
31 if __name__ == '__main__':
32     main()

 

2.threading模块

threading模块的主要方法:

threading.active_count():Return the number of Thread objects currently alive. The returned count is equal to the length of the list returned by enumerate().

threading.current_thread():Return the current Thread object, corresponding to the caller’s thread of control.

threading.get_ident():Return the ‘thread identifier’ of the current thread.

threading.enumerate():Return a list of all Thread objects currently alive.

threading.main_thread():Return the main Thread object. In normal conditions, the main thread is the thread from which the Python interpreter was started.

threading.settrace(func):Set a trace function for all threads started from the threading module. The func will be passed to sys.settrace() for each thread, before its run() method is called.

threading模块的对象包括:

Thread 表示一个执行线程的对象

Lock

锁(和thread中的锁一样)
RLock 可重入锁,使单一线程可以获得已有的锁(锁递归)
Condition 条件变量,使一个线程等待另一个线程满足特定的条件
Event 条件变量的通用版本,任意数量的线程等待某个事件的发生,在该事件发生后所有线程将被激活
Semaphore 为线程间共享的有限资源提供一个“计数器”,如果没有可用资源会被阻塞
BoundedSemphore 与semaphore相似,不过它不允许超过初始值
Timer 与Thread相似,不过它在运行前等待一段时间
Barrier 创建一个“障碍”,必须达到指定数量的线程后才可以继续

2.1 Thread类

Thread类可以用来启动新的线程,有2种方法:第一通过__init__()将方法传进来,第二通过一个子类来重写run()方法。

Thread对象数据属包括:name(线程名),ident(线程的标识符),daemon(线程是否为守护线程),如果一个线程是守护线程,那表示这个线程是不重要的,进程退出时不需要等待这个线程执行完。

Thread对象的方法有:

__init__(group=None,target=None,args=(),kwargs={},verbose=None,daemon=None):实例化一个线程对象,需要一个可调用的target,以及参数。

start():开始执行线程

run():定义线程的功能的方法,通常在子类中被应用开发者重写。

join(timeout=None):直至启动的线程终止之前一直被挂起,除非给出了timeout,不然一直被阻塞。

getName():返回线程名

setName(name):设定线程名

另外还有is_alive/isAlive、isDaemon()、setDaemon()等

在有了threading以后,上面的例子可以用threading中模块和方法来实现:

 1 from time import sleep, ctime
 2 import threading
 3 
 4 loops = [4,2]
 5 
 6 def loop(nloop, nsec):
 7     print('start loop', nloop, 'at:',ctime())
 8     sleep(nsec)
 9     print('loop', nloop, 'done at:', ctime())
10     
11 def main():
12     print('starting at:', ctime())
13     threads = []
14     nloops = range(len(loops))
15     
16     for i in nloops:
17         t = threading.Thread(target=loop, args=(i, loops[i]))
18         threads.append(t)
19         
20     for i in nloops:
21         threads[i].start()
22         
23     for i in nloops:
24         threads[i].join()
25             
26     print('all Done at:', ctime())
27     
28 if __name__ == '__main__':
29     main()

 另外一种启动多线程的方法,使用子类继承Thread类,并重写run方法

 1 from time import sleep, ctime
 2 import threading
 3 
 4 loops = [4,2]
 5 
 6 class MyThread(threading.Thread):
 7     def __init__(self, func, args, name=''):
 8         threading.Thread.__init__(self)
 9         self.name = name
10         self.func = func
11         self.args = args
12         
13     def run(self):
14         self.func(*self.args)
15 
16 def loop(nloop, nsec):
17     print('start loop', nloop, 'at:',ctime())
18     sleep(nsec)
19     print('loop', nloop, 'done at:', ctime())
20     
21 def main():
22     print('starting at:', ctime())
23     threads = []
24     nloops = range(len(loops))
25     
26     for i in nloops:
27         t = MyThread(loop, (i, loops[i]), loop.__name__)
28         print(loop.__name__)
29         threads.append(t)
30         
31     for i in nloops:
32         threads[i].start()
33         
34     for i in nloops:
35         threads[i].join()
36             
37     print('all Done at:', ctime())
38     
39 if __name__ == '__main__':
40     main()

 

2.2锁

在threading模块中,提供了2种锁:threading.Lock()、threading.RLock()

Lock的用法:

 1 import threading
 2 from random import randint
 3 from time import sleep, ctime
 4 
 5 L = threading.Lock()
 6 
 7 def hi(n):
 8     #L.acquire()
 9     for i in [1,2]:
10         print(i)
11         sleep(n)
12         print('Zzzz, sleep:', n)
13     #L.release()
14     
15 def main():
16     print('### Start at:', ctime())
17     threads = []
18     
19     for i in range(10):
20         rands = randint(1,2)
21         t = threading.Thread(target=hi, args=(rands,))
22         threads.append(t)
23         
24     for i in range(10):
25         threads[i].start()
26         
27     for i in range(10):
28         threads[i].join()
29         
30     print('### Done at:', ctime())
31     
32 if __name__ == '__main__':
33     main()

 

2.3信号量

threading模块包括两种信号量:Semaphore和BoundedSemaphore。信号量实际上就是计数器,它们从固定数量的有限资源起始,当分配一个单位的资源时,计数器减1,而当一个单位的资源返回资源池时,计数器值加1。BoundedSemaphore的一个额外功能是这个计数器的值永远不会超过它的初始值。

 1 import threading 
 2 import time
 3 import random
 4 
 5 semaphore = threading.Semaphore(0)
 6 
 7 def consumer():
 8     print("consumer is waiting.")
 9     semaphore.acquire()
10     print("Consumer notify: consumed item number %s." % item)
11 
12 def producer():
13     global item
14     time.sleep(10)
15     item = random.randint(1, 1000)
16     print("producer nofity: produced item number %s." % item)
17     semaphore.release()  
18 
19 
20 
21 if __name__ == "__main__":
22 
23     for i in range(0, 5):
24         t1 = threading.Thread(target=producer)
25         t2 = threading.Thread(target=consumer)
26         t1.start()
27         t2.start()
28         t1.join()
29         t2.join()
30     print("program teminated.")

 

2.4Event

Event内部包含了一个标志位,初始的时候为false。
可以使用使用set()来将其设置为true;
或者使用clear()将其从新设置为false;
可以使用is_set()来检查标志位的状态;
另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

实例: (线程间相互通信)

 1 import threading  
 2 import time  
 3  
 4 class MyThread1(threading.Thread):  
 5     def __init__(self, signal):  
 6         threading.Thread.__init__(self)  
 7         self.singal = signal  
 8  
 9     def run(self):  
10         print("I am %s,I will sleep ..."%self.name) 
11         self.singal.wait()  
12         print("I am %s, I awake..." %self.name)
13 
14 class MyThread2(threading.Thread):  
15     def __init__(self, signal):  
16         threading.Thread.__init__(self)  
17         self.singal = signal  
18  
19     def run(self):  
20         print("sleep 3 seconds") 
21         self.singal.set()
22         
23 if __name__ == "__main__":  
24     event = threading.Event()  
25     thread1 = MyThread1(event)
26     thread1.start()
27 
28     thread2 = MyThread2(event)
29     thread2.start()
30     print ("main thread sleep 10 seconds... ")  
31     time.sleep(10)  

 

Python由于GIL的限制,多线程更适合于I/O密集型应用,而不是计算密集型应用,为了更好的实现并行,需要使用多进程,如:subprocess模块和multiprocessing模块

posted @ 2017-05-24 16:07  哈利波波特  阅读(10)  评论(0)    收藏  举报