Python读书笔记(四)---多线程编程
python提供了多个模块来支持多线程编程。
1._thread模块(python2中为thread)
_thread.start_new_thread(function, args[, kwargs]):
启动一个新线程,并返回它的标识符。function代表函数名,args是一个tuple型的参数,若为空就是()。函数返回后,线程就自动退出。
_thread.allocate_lock():
返回一个lock object
lock.acquire(waitflag=1, timeout=-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模块

浙公网安备 33010602011771号