线程python
多任务能够由多进程
完成,也能够由一个进程内的多线程
完成。安全
咱们前面提到了进程是由若干线程
组成的,一个进程
至少有一个线程
。多线程
因为线程是操做系统直接支持的执行单元,所以,高级语言一般都内置多线程的支持,Python也不例外,而且,Python的线程是真正的Posix Thread,而不是模拟出来的线程。函数
Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。绝大多数状况下,咱们只须要使用threading
这个高级模块ui
函数方式
建立线程:操作系统
import threading import time def func1(): i = 0 while i<5 : print('eating......') time.sleep(1) i+=1 def func2(): i = 0 while i<5 : print('running......') time.sleep(1) i+=1 if __name__ == '__main__': t1 = threading.Thread(target=func1) t2 = threading.Thread(target=func2) t1.start() #开始线程 t2.start() t1.join() t2.join() >>> eating...... running...... eating...... running...... eating...... running......
类的方式:线程
import threading,time class Mythread(threading.Thread): def __init__(self,*args,**kwargs): name = kwargs.pop('args') self._heroname = name super(Mythread, self).__init__(*args,**kwargs) def run(self): print('currentThread is %s'%threading.currentThread()) print('hero name %s'%self._heroname) print(self.name) t1 = Mythread(args=('鲁班七号')) t2 = Mythread(args='赵云') t3 = Mythread(args='后裔') t1.start() t2.start() t3.start() >>> currentThread is <Mythread(Thread-1, started 3924)> hero name 鲁班七号 Thread-1 currentThread is <Mythread(Thread-2, started 11416)> hero name 赵云 Thread-2 currentThread is <Mythread(Thread-3, started 5868)> hero name 后裔 Thread-3
多线程共享全局变量code
多线程中,全部变量都由全部线程共享,因此,任何一个变量均可以被任何一个线程修改,所以,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了
数据混乱:对象
import threading g_nums = 0 def test1(): global g_nums for x in range(1000000): g_nums+=1 def test2(): global g_nums for x in range(1000000): g_nums+=1 if __name__ == '__main__': t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) t1.start() t2.start() t1.join() t2.join() print(g_nums) >>> 1320177
互斥锁递归
当线程同时修改末一个共享数据
时,须要进行同步控制。
线程同步可以保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁
保证共享数据操做的完整性。每一个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
import threading from threading import Lock lock = Lock() g_nums = 0 def test1(): global g_nums lock.acquire() for x in range(1000000): g_nums+=1 lock.release() def test2(): global g_nums lock.acquire() for x in range(1000000): g_nums+=1 lock.release() if __name__ == '__main__': t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) t1.start() t2.start() t1.join() t2.join() print(g_nums) >>> 2000000
RLock(可重入锁)
是一个能够被同一个线程请求屡次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock
被某个线程拥有。拥有RLock
的线程能够再次调用acquire()
,释放锁时须要调用release()
相同次数。
能够认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
简言之:Lock属于全局,Rlock属于线程
Lock对比Rlock #coding:utf-8 import threading lock = threading.Lock() #Lock对象 lock.acquire() lock.acquire() #产生了死锁。 lock.release() lock.release() print lock.acquire() import threading rLock = threading.RLock() #RLock对象 rLock.acquire() rLock.acquire() #在同一线程内,程序不会堵塞。 rLock.release() rLock.release()
Condition(条件变量)一般与一个锁关联。须要在多个Contidion中共享一个锁时,能够传递一个Lock/RLock实例给构造方法,不然它将本身生成一个RLock实例。
能够认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另外一个线程调用notify()/notifyAll()通知;获得通知后线程进入锁定池等待锁定。
构造方法:
Condition([lock/rlock])
实例方法:
acquire([timeout])/release():
调用关联的锁的相应方法。
wait([timeout]):
调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已得到锁定,不然将抛出异常。
notify():
调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试得到锁定(进入锁定池);其余线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已得到锁定,不然将抛出异常。
notifyAll():
调用这个方法将通知等待池中全部的线程,这些线程都将进入锁定池尝试得到锁定。调用这个方法不会释放锁定。使用前线程必须已得到锁定,不然将抛出异常。
例子1:生产者消费者:
# encoding: UTF-8 import threading import time # 商品 product = None # 条件变量 con = threading.Condition() # 生产者方法 def produce(): global product if con.acquire(): while True: if product is None: print( 'produce...') product = 'anything' # 通知消费者,商品已经生产 con.notify() # 等待通知 con.wait() time.sleep(2) # 消费者方法 def consume(): global product if con.acquire(): while True: if product is not None: print( 'consume...') product = None # 通知生产者,商品已经没了 con.notify() # 等待通知 con.wait() time.sleep(2) t1 = threading.Thread(target=produce) t2 = threading.Thread(target=consume) t2.start() t1.start() >>> produce... consume... produce... consume... produce... consume... ......
例子2:生产者消费者
import threading import time condition = threading.Condition() products = 0 class Producer(threading.Thread): def run(self): global products while True: if condition.acquire(): if products < 10: products += 1 print( "Producer(%s):deliver one, now products:%s" %(self.name, products)) condition.notify()#不释放锁定,所以须要下面一句 condition.release() else: print( "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)) condition.wait()#自动释放锁定 time.sleep(2) class Consumer(threading.Thread): def run(self): global products while True: if condition.acquire(): if products > 1: products -= 1 print( "Consumer(%s):consume one, now products:%s" %(self.name, products)) condition.notify() condition.release() else: print( "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)) condition.wait() time.sleep(2) if __name__ == "__main__": for p in range(0, 2): p = Producer() p.start() for c in range(0, 3): c = Consumer() c.start() >>> Producer(Thread-1):deliver one, now products:1 Producer(Thread-2):deliver one, now products:2 Consumer(Thread-3):consume one, now products:1 Consumer(Thread-4):only 1, stop consume, products:1 Consumer(Thread-5):only 1, stop consume, products:1 Producer(Thread-2):deliver one, now products:2 ...
Event事件
Event(事件)
是最简单的线程通讯机制之一:一个线程通知事件,其余线程等待事件。Event内置了一个初始为False的标志,当调用set()
时设为True
,调用clear()
时重置为False
。wait()
将阻塞线程至等待阻塞状态。
Event其实就是一个简化版的Condition
。Event没有锁,没法使线程进入同步阻塞状态。
构造方法:
Event()
实例方法:
1.isSet():
当内置标志为True时返回True。
2.set():
将标志设为True,并通知全部处于等待阻塞状态的线程恢复运行状态。
clear():
将标志设为False。wait([timeout]):
若是标志为True将当即返回,不然阻塞线程至等待阻塞状态,等待其余线程调用set()。# encoding: UTF-8 import threading import time event = threading.Event() def func(): # 等待事件,进入等待阻塞状态 print( '%s wait for event...' % threading.currentThread().getName()) event.wait() # 收到事件后进入运行状态 print( '%s recv event.' % threading.currentThread().getName()) t1 = threading.Thread(target=func) t2 = threading.Thread(target=func) t1.start() t2.start() time.sleep(2) # 发送事件通知 print( 'MainThread set event.') event.set() >>> Thread-1 wait for event... Thread-2 wait for event... MainThread set event. Thread-2 recv event. Thread-1 recv event.
Event对象关键的特性是他会唤醒全部的线程。若是咱们编写的程序只但愿唤醒一个单独的线程,那么最好使用Semaphore或者Condition对象
#encoding:utf-8 # __author__ = 'donghao' # __time__ = 2019/4/1 21:30 import threading import time def worker(n, seam): seam.acquire() print('working',n) time.sleep(1) if __name__ == '__main__': seam = threading.Semaphore(0) nworkers = 10 for n in range(10): t = threading.Thread(target=worker, args=(n, seam,)) t.start() while True: time.sleep(1) seam.release() >>> working 0 working 1 working 2 working 3 working 4 working 5 working 6 ......
timer类
Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。
构造方法:
Timer(interval, function, args=[], kwargs={})
# encoding: UTF-8 import threading def func(): print( 'hello timer!') timer = threading.Timer(5, func) timer.start()
local类
local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程没法访问其余线程设置的属性;线程设置的属性不会被其余线程设置的同名属性替换。
能够把local当作是一个“线程-属性字典”的字典,local封装了从自身使用线程做为 key检索对应的属性字典、再使用属性名做为key检索属性值的细节。
`# encoding: UTF-8 import threading local = threading.local() local.tname = '王者荣耀' def func(): local.tname = '鲁班七号' print(local.tname) t1 = threading.Thread(target=func) t1.start() t1.join() print(local.tname) >>> 鲁班七号 王者荣耀