Python中创建线程有两种方式:函数或者用类来创建线程对象。
- 函数式:调用 _thread 模块中的start_new_thread()函数来产生新线程。
- 类:创建threading.Thread的子类来包装一个线程对象。
一.函数式:调用thread模块中的start_new_thread()函数来产生新线程
thread.start_new_thread ( function, args[, kwargs] )
- function - 线程函数
- args - 传递给线程函数的参数,他必须是个tuple类型
- kwargs - 可选参数
例:通过thread来创建新线程
import thread,time def timer(name,delay): count = 0 while count < 5: time.sleep(delay) count +=1 print "%s:%s" %(name,time.ctime()) #创建两个线程 thread.start_new_thread(timer,('Thread-1',2,)) #timer表示执行timer函数,后面元组内表示timer函数的两个参数 thread.start_new_thread(timer,('Thread-2',4,)) while 1: pass
输出结果:
Thread-1:Tue Oct 18 16:05:23 2016 Thread-1:Tue Oct 18 16:05:25 2016 Thread-2:Tue Oct 18 16:05:25 2016 Thread-1:Tue Oct 18 16:05:27 2016 Thread-1:Tue Oct 18 16:05:29 2016 Thread-2:Tue Oct 18 16:05:29 2016 Thread-1:Tue Oct 18 16:05:31 2016 Thread-2:Tue Oct 18 16:05:33 2016 Thread-2:Tue Oct 18 16:05:37 2016 Thread-2:Tue Oct 18 16:05:41 2016
二.类:创建threading.Thread的子类来包装一个线程对象
例1,通过threading来创建新线程:
import threading,time def show(arg): time.sleep(2) print 'thread' + str(arg) for i in range(10): t = threading.Thread(target=show,args=(i,)) #target=show执行show函数,后面args表示show函数中传入的参数 t.start()
运行结果:
Main thread stop. Tue Oct 18 11:44:41 2016 thread0 thread2 thread4 thread3 thread1 thread8 thread6 thread5 thread7 thread9
例2:单线程
from time import ctime,sleep def Music(music): for i in range(2): print ('I am listening to the music now...%s' %ctime()) sleep(2) def Movie(movie): for i in range(2): print('I am watching movie now...%s' %ctime()) sleep(5) if __name__ == '__main__': Music('Goodbye') Movie('Who Am I') print ('Main Process is over...%s' %ctime())
输出结果:
I am listening to the music now...Mon Dec 12 14:53:24 2016 I am listening to the music now...Mon Dec 12 14:53:26 2016 I am watching movie now...Mon Dec 12 14:53:28 2016 I am watching movie now...Mon Dec 12 14:53:33 2016 Main Process is over...Mon Dec 12 14:53:38 2016
例3:多线程
import threading import time def Music(music): for i in range(2): print('I am listening to the <%s> now...%s' %(music,time.ctime())) time.sleep(2) def Movie(movie): for i in range(2): print('I am watching <%s> now...%s' %(movie,time.ctime())) time.sleep(5) t1 = threading.Thread(target=Music,args=('I Will',)) t2 = threading.Thread(target=Movie,args=('The Walking Dead',)) if __name__ == '__main__': #t1.daemon = True #如果为True,说明该线程为守护线程,也就表明这个线程不重要,在主线程退出的时候不用等待这个线程 #t2.daemon = True #如果想等待子线程执行完之后,主线程才退出,就不需要设置daemon属性(daemon属性默认就为False) t1.start() t2.start() #t1.join() #停止主线程,直到执行完子线程t1后才执行主线程 #t2.join() #停止主线程,直到执行完子线程t2后才执行主线程 print('all is over...%s' %time.ctime())
输出结果:
I am listening to the <I Will> now...Mon Dec 12 14:41:48 2016 #与另外一条子线程同时运行的,注意时间! I am watching <The Walking Dead> now...Mon Dec 12 14:41:48 2016 all is over...Mon Dec 12 14:41:48 2016 I am listening to the <I Will> now...Mon Dec 12 14:41:50 2016 I am watching <The Walking Dead> now...Mon Dec 12 14:41:53 2016
上面例题中如果启用t1.join和t2.join结果如下:
I am listening to the <I Will> now...Mon Dec 12 14:42:56 2016 I am watching <The Walking Dead> now...Mon Dec 12 14:42:56 2016 I am listening to the <I Will> now...Mon Dec 12 14:42:58 2016 I am watching <The Walking Dead> now...Mon Dec 12 14:43:01 2016 all is over...Mon Dec 12 14:43:06 2016 #等待子线程运行结束后才执行主线程
Threading模块中所有对象:
1,Thread
- start() #开始线程的执行
- run() #定义线程的功能的函数(一般会被子类重写)
- join(timeout=None) #程序挂起,直到该线程执行结束(如果设置了timeout,最多阻塞timeout秒)
- getName() #返回线程名字
- setName(name) #设置线程名字
- isAlive() #查看该线程是否还在运行
- isDaemon(False) #设置守护进程(True)或非守护线程(默认为False),如果设置为守护线程(True)表示该线程不重要,主线程无需等待该线程结束才退出。
2,Lock(Rlock):只允许一个线程更改数据。提供acquire方法(获取锁)和release方法(释放锁)
- RLock和Lock 的区别:RLock允许在同一线程中被多次acquire和release。RLock中acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。而Lock不一样,同一线程只能使用一次acquire和release方法。
3,condition
4,Event
5,Semaphore(BoundedSemaphore):同时允许一定数量的线程更改数据,信号量也提供acquire方法和release方法。
6,其他函数:
activeCount() #返回当前活动线程的数量 currentThread() #返回当前线程 enumerate() #返回当前活动线程的列表 settrace(func) #为所有线程设置一个跟踪函数 setprofile() #为所有线程设置一个profile函数
多线程实现同步的方法:
1.线程锁:在同一个进程中的资源,所有线程都是共享的。线程之间是进行随机调度,如果不同线程同时对数据进行修改,就会产生问题。为了保证数据的准确性,引入了锁的概念。也就是在同一时刻只允许一个线程操作该数据。
锁有两种状态:锁定和未锁定
每当一个线程1要访问共享数据时,必须先获得锁定;如果已经有别的线程2获得锁定了,那么就让线程1暂停,也就是同步阻塞;等到线程2访问完毕,释放锁以后,再让线程1继续。
使用锁方法:
lock = threading.Lock() #创建锁 lock.acquire([timeout]) #锁定 lock.release() #释放
例1:未使用锁之前:(注意同一时间点,num值的变化)
import threading import time num = 0 def fun(arg): global num time.sleep(1) num += 1 print(num,'-->','%s'%time.ctime()) for item in range(5): #开启5个子线程 t = threading.Thread(target=fun,args=(item,)) t.start() print('Main threading stop !')
输出结果:
Main threading stop ! 1 --> Mon Dec 12 15:51:03 2016 2 --> Mon Dec 12 15:51:03 2016 3 --> Mon Dec 12 15:51:03 2016 #同一时间点输出的num都不一样 4 --> Mon Dec 12 15:51:03 2016 5 --> Mon Dec 12 15:51:03 2016
例2:使用锁之后:
import threading import time num = 0 lock = threading.Lock() #创建锁 def fun(arg): lock.acquire() #获取锁 global num time.sleep(1) num += 1 print(num,'-->','%s'%time.ctime()) lock.release() #释放锁 for item in range(5): #开启5个子线程 t = threading.Thread(target=fun,args=(item,)) t.start() print('Main threading stop !')
输出结果:
Main threading stop ! 1 --> Mon Dec 12 15:56:34 2016 2 --> Mon Dec 12 15:56:35 2016 3 --> Mon Dec 12 15:56:36 2016 #注意:同一时间点num值不变 4 --> Mon Dec 12 15:56:37 2016 5 --> Mon Dec 12 15:56:38 2016
2,信号量Semaphore
例:
import threading import time se = threading.Semaphore(5) #同时允许5个线程修改数据 def fun(n): se.acquire() time.sleep(1) print('thread:%s -->%s'%(n,time.ctime())) se.release() if __name__ == '__main__': for i in range(10): t = threading.Thread(target=fun,args=(i,)) t.start()
输出结果:
thread:0 -->Mon Dec 12 16:36:12 2016 thread:1 -->Mon Dec 12 16:36:12 2016 thread:3 -->Mon Dec 12 16:36:12 2016 thread:2 -->Mon Dec 12 16:36:12 2016 thread:4 -->Mon Dec 12 16:36:12 2016 #同一时间点,允许5个线程同时修改值 thread:6 -->Mon Dec 12 16:36:13 2016 thread:8 -->Mon Dec 12 16:36:13 2016 thread:5 -->Mon Dec 12 16:36:13 2016 thread:9 -->Mon Dec 12 16:36:13 2016 thread:7 -->Mon Dec 12 16:36:13 2016
3,时间event:通用的条件变量,多个线程可以等待某个事件发生后,所有线程都被激活。事件主要提供了三个方法 set、wait、clear。
事件处理的机制:
全局定义了一个“Flag”:
(1)如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞
(2)如果“Flag”值为True,那么event.wait 方法时便不再阻塞
clear:将“Flag”设置为False
set:将“Flag”设置为True
import threading eve = threading.Event() def fun(e): print('start...') e.wait() print('execute...') for i in range(5): t = threading.Thread(target=fun,args=(eve,)) t.start() eve.clear() usr_input = input('Enter the flag:') if usr_input =='1': eve.set()
输出结果:
start... start... start... start... start... Enter the flag:1 execute... execute... execute... execute... execute...
4,条件Condition:使线程进入等待状态,当满足某个条件时,才释放线程。
notify()方法会唤醒一个在等待conditon变量的线程;notify_all() 则会唤醒所有在等待conditon变量的线程
例如生产者模型:
import threading import time c = threading.Condition() def fun(n): c.acquire() c.wait() print('current threading:%s ---> %s' %(n,time.ctime())) time.sleep(1) c.release() if __name__ == '__main__': for i in range(10): t = threading.Thread(target=fun,args=(i,)) t.start() while True: usr_input = input('Enter:') if usr_input == 'q': break c.acquire() c.notify(int(usr_input)) c.release()
输出结果:
Enter:3 current threading:1 ---> Mon Dec 12 17:14:40 2016 current threading:2 ---> Mon Dec 12 17:14:41 2016 current threading:0 ---> Mon Dec 12 17:14:39 2016 current threading:0 ---> Mon Dec 12 17:14:39 2016 Enter:5 current threading:4 ---> Mon Dec 12 17:14:47 2016 current threading:6 ---> Mon Dec 12 17:14:48 2016 current threading:3 ---> Mon Dec 12 17:14:49 2016 current threading:5 ---> Mon Dec 12 17:14:50 2016 current threading:7 ---> Mon Dec 12 17:14:51 2016 Enter:3 current threading:9 ---> Mon Dec 12 17:14:59 2016 current threading:8 ---> Mon Dec 12 17:15:00 2016 Enter:q Process finished with exit code 0
5.定时器:指定n秒后执行某操作
import threading import time print('Time:%s'%time.ctime()) def Print(): print('hello,python...%s'%time.ctime()) t = threading.Timer(2,Print) #2秒后执行Print函数 t.start()
输出结果:
Time:Mon Dec 12 17:24:50 2016 hello,python...Mon Dec 12 17:24:52 2016 #2秒后执行
同步队列Queue:
- Queue模块提供了同步队列和线程安全。包括FIFO队列、LIFO队列以及优先级队列。可以使用队列来实现线程间的同步。
FIFO:(默认为FIFO)
- Queue模块可以用来进行线程间通讯,让各个线程之间共享数据。
- Queue解决了生产者,消费者的问题。
Queue模块常用方法:
import queue #导入queue模块 q = queue.Queue(maxsize=0) #构造一个FIFO队列。maxsize指定队列的长度。为0时,表示队列长度无限制。 q.put(item='n',block=1,timeout=None) #在队尾插入一个item(必选项)。如果当前队列为空,且block为1(默认值)时,put()方法就使 #线程暂停,一直阻塞到队列中有空间为止;如果block为0,put()方法会引发Full异常。 q.get(block=1,timeout=None) #从队首删除并返回一个项目。当block为1(默认值)时,get()方法使线程暂停,直到有项目可用。如果队列为空,且block为0时,队列将引发empty异常。 q.put_nowait(item='n') #相当于q.put(item,False) q.get_nowait() #相当于q.get(False) q.join() #等到队列为空时,在执行别的操作 q.qsize() #返回队列的大小 q.empty() #当队列为空时,返回True,否则返回False q.full() #当队列满时,返回True,否则返回False q.task_done() #在完成一项工作之后,它向任务已完成的队列发送一个信号
例:
from threading import Thread from queue import Queue import time class Producer(Thread): #定义生产者类 def __init__(self,name,queue): self.Name = name self.Queue = queue super(Producer,self).__init__() #执行父类的构造函数 def run(self): #生产者具体工作内容 while True: if self.Queue.full(): time.sleep(1) else: self.Queue.put('产品') time.sleep(1) print ('%s生产一个产品' %(self.Name,)) #Thread.run(self) class Consumer(Thread): #定义消费者类 def __init__(self,name,queue): self.Name = name self.Queue = queue super(Consumer, self).__init__() #执行父类的构造函数 def run(self): while True: if self.Queue.empty(): time.sleep(1) else: self.Queue.get('产品') time.sleep(1) print ('%s消费了一个产品' %(self.Name,)) #Thread.run(self) que = Queue(maxsize=100) #定义容器 person1 = Producer('P1',que) #创建生产者P1 person1.start() person2 = Producer('P2',que) #创建生产者P2 person2.start() person3 = Producer('P3',que) #创建生产者P3 person3.start() for num in range(20): #创建消费者20人:C1,C2...C20 name = 'C1%d' %(num,) item = Consumer(name,que) item.start()