| 
                         <div class="toc"> 
<p class="toc-title">目录  
<div class="toc-list">
线程同步,即线程之间协同工作,一个线程访问某些数据时,其他线程不能访问这些数据,直到该线程完成对数据的操作。 
不同的操作系统实现的技术有所不同,有临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)等。 
 
Event是线程间通信的最简单的方法:通过一个线程发出信号,其他线程等待它。 
Event对象管理一个内部标志,该标志通过set()方法设置为true,也可以通过clear()方法重置为false,使用wait()方法时,将会被阻塞,直到该标志为真的时候,才放行。该标志一开始是false。 
from threading import Event,Thread
import logging
import time
FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s' 
logging.basicConfig(format=FORMAT,level=logging.INFO) 
def boss(event:Event): 
logging.info("I'm boss,wait...") 
event.wait()  # 阻塞,直到为true 
logging.info("good,thanks!") 
def worker(event:Event,counts): 
logging.info("I'm working for boss.") 
cups = [] 
while True: 
logging.info("make 1 cup") 
cups.append(1) 
time.sleep(0.5) 
logging.info(cups) 
if len(cups) >= counts: 
event.set()  # 完成,标记为true 
break 
logging.info("I finished my job,cups={}".format(cups)) 
event = Event() 
b = Thread(target=boss,args=(event,)) 
w = Thread(target=worker,10)) 
w.start() 
b.start() 
<h3 id="lock"><font color="#1E90FF" size="4"> Lock  
锁,如果存在共享资源争抢的问题,就可以使用锁,从而保证一个使用者可以完全拥有这个资源。 
Lock拥有两种基本方法,acquire()和release()。acquire将状态改为锁定,此时将会阻塞,直到调用relase()解锁。relase()方法只能在锁定的时候调用,否则将会应发RuntimeError异常。锁还支持上下文管理协议,锁的所有方法都是原子方式进行。 
例子:车间生产1000个杯子,组织10人生产时,结果会超出数量(没有使用锁)
from threading import Thread,Lock
import logging
import time
FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s' 
logging.basicConfig(format=FORMAT,level=logging.INFO) 
cups = [] 
def worker(counts=10): 
logging.info("I'm working for boss") 
while len(cups) < counts: 
time.sleep(0.0002) 
cups.append(1) 
logging.info("I'm finished,cups={}".format(len(cups))) 
for _ in range(10): 
Thread(target=worker,args=(1000,)).start() 
结果
'''''' 
2019-03-06 07:31:50,884 Thread-10 11052 I'm working for boss 
2019-03-06 07:31:51,084 Thread-3 7108 I'm finished,cups=1000 
2019-03-06 07:31:51,084 Thread-7 21188 I'm finished,cups=1001 
2019-03-06 07:31:51,084 Thread-8 11592 I'm finished,cups=1002 
2019-03-06 07:31:51,085 Thread-5 18288 I'm finished,cups=1003 
2019-03-06 07:31:51,085 Thread-10 11052 I'm finished,cups=1004 
''''''  
使用锁后。 
from threading import Thread,level=logging.INFO)
cups = [] 
lock = Lock() 
def worker(counts=10): 
logging.info("I'm working for boss") 
flag = False 
while True: 
lock.acquire() # 加锁 
if len(cups) >= counts: 
flag = True 
time.sleep(0.0002) 
if not flag: 
cups.append(1) 
lock.release() #生产完之后,解锁 
if flag: 
break 
logging.info("I'm finished,)).start()</code></pre> 
<h3 id="rlock"><font color="#1E90FF" size="4"> RLock  
RLock:可重入锁,是线程相关的锁。 
线程A获得可重入锁,可以多次获取,不会阻塞,但是最后在线程A中做和acquire次数相同的release才会释放。当锁没有释放完,其他线程取锁就会阻塞。 
from threading import Thread,Lock,RLock
import logging
import time
FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s' 
logging.basicConfig(format=FORMAT,level=logging.INFO) 
def say(l:RLock): 
l.acquire()  # 获取一次 
logging.info("acquire1") 
l.acquire()  # 获取2次 
logging.info("acquire2") 
l.release()  # 释放1次 
logging.info("release1") 
l.release()  # 释放2次 
logging.info("release2") 
rlock = RLock() 
t1 = Thread(target=say,args=(rlock,),name="t1") 
t2 = Thread(target=say,name="t2") 
t1.start() 
t2.start() 
结果
2019-03-06 20:41:40,830 t1 2036 acquire1 
2019-03-06 20:41:40,830 t1 2036 acquire2 
2019-03-06 20:41:40,830 t1 2036 release1 
2019-03-06 20:41:40,830 t1 2036 release2 
2019-03-06 20:41:40,831 t2 31984 acquire1 
2019-03-06 20:41:40,831 t2 31984 acquire2 
2019-03-06 20:41:40,831 t2 31984 release1 
2019-03-06 20:41:40,831 t2 31984 release2  
从结果也可以看出来,只有t1线程完全释放了相同次数的锁,t2线程才能获得锁。 
条件变量Condition,总是和某种锁(通常是RLock)相互关联。条件变量也支持上下文管理协议。 
生产者消费者模型:
from threading import Event,Thread,Condition
import logging
import time
import random
class Dispatcher: 
def init(self): 
self.data = 0 
self.cond = Condition() 
def produce(self):
    print("开始生产包子")
    while True:
        with self.cond:
            self.data += 1
            print("生产了一个包子,现在有{}个。".format(self.data))
            self.cond.notify()
        time.sleep(1)
def consume(self):
    print("开始买包子了...")
    while True:
        with self.cond:
            if self.data <= 5:
                self.cond.wait()
                print("包子太少了,等着了...")
            else:
                self.data -= 1
                print("我买了1个包子,还有{}个。".format(self.data))
                self.cond.notify()
        time.sleep(2) 
d = Dispatcher() 
for i in range(2): 
Thread(target=d.produce).start() 
for j in range(4): 
Thread(target=d.consume).start() 
  
结果 
开始生产包子
生产了一个包子,现在有1个。
开始生产包子
生产了一个包子,现在有2个。
开始买包子了...
开始买包子了...
开始买包子了...
开始买包子了...
生产了一个包子,现在有3个。
包子太少了,等着了...
生产了一个包子,现在有4个。
包子太少了,等着了...
生产了一个包子,现在有5个。
包子太少了,等着了...
生产了一个包子,现在有6个。
包子太少了,等着了...
生产了一个包子,现在有7个。
我买了1个包子,还有6个。
生产了一个包子,现在有7个。 
                        (编辑:莱芜站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                    
  |