1、线程同步
线程同步,线程间协同,通过某种技术,让一个线程访问某些数据时,其他线程不能访问这些数据,直到该线程完成对数的操作做。
不同操作系统实现技术有所不同,有 临界区(Critical Section),互斥量(Mutex), 信号量(Semaphore),时间Event等
2、Event
Even事件,是线程间通信机制中最简单的实现,使用一个内部的标记flag,通过flag的True或False的变化来进行操作。
名称
含义
set()
标记设置为True
clear()
标记设置为False
is_set()
标记是否为True
wait(timeout=None)
设置等待标记为True的时长,None为无限等待,等到返回True,未等到超时了,返回False
测试:需求:老板雇了一个员工,让他生成杯子,老板一直等待这个工人,知道生产了10个杯子。
1、普通线程实现:
1 importthreading2 importtime3
4 flag =False5
6 def worker(count=10):7 print('im working')8 globalflag9 cpus =[]10 whileTrue:11 time.sleep(0.1)12 cpus.append(1)13 if len(cpus) > 10:14 flag =True15 break
16 print(cpus)17
18 defboss():19 globalflag20 whileTrue:21 time.sleep(2)22 ifflag:23 print('good job')24 break
25
26 w = threading.Thread(target=worker)27 b = threading.Thread(target=boss)28 w.start()29 b.start()
View Code
结果:
1 im working2 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]3 good job4
5 Process finished with exit code 0
View Code
2、利用Event 类实现:
1 from threading importEvent, Thread2 importlogging3 importtime4
5 FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
6 logging.basicConfig(format=FORMAT, level=logging.INFO)7
8 defboss(event:Event):9 logging.info('boss')10 event.wait()11 logging.info('good job')12
13 def worker(event:Event, count=10):14 logging.info('working')15 cups =[]16 whileTrue:17 logging.info('make 1')18 time.sleep(0.5)19 cups.append(1)20 if len(cups) >=count:21 event.set()22 break
23 logging.info('finished {}'.format(cups))24
25 event =Event()26 w = Thread(target=worker, args=(event,))27 b = Thread(target=boss, args=(event,))28 w.start()29 b.start()
View Code
结果:
1 2018-10-12 10:58:11,515 Thread-1 8448working2 2018-10-12 10:58:11,515 Thread-1 8448 make 1
3 2018-10-12 10:58:11,515 Thread-2 1064boss4 2018-10-12 10:58:12,030 Thread-1 8448 make 1
5 2018-10-12 10:58:12,545 Thread-1 8448 make 1
6 2018-10-12 10:58:13,060 Thread-1 8448 make 1
7 2018-10-12 10:58:13,574 Thread-1 8448 make 1
8 2018-10-12 10:58:14,089 Thread-1 8448 make 1
9 2018-10-12 10:58:14,604 Thread-1 8448 make 1
10 2018-10-12 10:58:15,119 Thread-1 8448 make 1
11 2018-10-12 10:58:15,634 Thread-1 8448 make 1
12 2018-10-12 10:58:16,148 Thread-1 8448 make 1
13 2018-10-12 10:58:16,663 Thread-1 8448 finished [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]14 2018-10-12 10:58:16,663 Thread-2 1064good job15
16 Process finished with exit code 0
View Code
总结:使用同一个Event实例的标记flag,谁wait 就是等到flag变为 True,或等到超时返回False,不限等待个数。
wait使用:
1 from threading importEvent, Thread2 importlogging3 importtime4
5 FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
6 logging.basicConfig(format=FORMAT, level=logging.INFO)7
8 defboss(event:Event):9 logging.info('boss')10 while event.wait(6):11 logging.info('good job')12 break
13
14
15 def worker(event:Event, count=10):16 logging.info('working')17 cups =[]18 whileTrue:19 logging.info('make 1')20 time.sleep(0.5)21 cups.append(1)22 if len(cups) >=count:23 event.set()24 break
25 logging.info('finished {}'.format(cups))26
27 event =Event()28 w = Thread(target=worker, args=(event,))29 b = Thread(target=boss, args=(event,))30 w.start()31 b.start()
View Code
Event练习:实现Timer,延时执行的线程,延时计add(x, y)
1 from threading importThread, Event2
3 classTimer:4 def __init__(self, interval, fn, args=(), kwargs={}):5 self.interval =interval6 self.fn =fn7 self.args =args8 self.kwargs =kwargs9 self.event =Event()10
11 defstart(self):12 Thread(target=self.run).start()13
14 defcancel(self):15 self.event.set()16
17 defrun(self):18 self.event.wait(self.interval)19 if notself.event.is_set():20 print(self.args, self.kwargs)21 self.fn(*self.args, **self.kwargs)22 self.event.set()23 defadd(x, y):24 print(x +y)25
26 t = Timer(4, add,(4, 5) )27 print(t.args, t.kwargs)28 t.start()29 #t.cancel()
30
31 print('--------------------------------')32 print('main thread exit')33 add(5, 6)
test
结果:
1 (4, 5) {}2 --------------------------------
3 main thread exit4 11
5 (4, 5) {}6 9
View Code
测试:cancel
1 from threading importThread, Event2
3 classTimer:4 def __init__(self, interval, fn, args=(), kwargs={}):5 self.interval =interval6 self.fn =fn7 self.args =args8 self.kwargs =kwargs9 self.event =Event()10
11 defstart(self):12 Thread(target=self.run).start()13
14 defcancel(self):15 self.event.set()16
17 defrun(self):18 self.event.wait(self.interval)19 if notself.event.is_set():20 self.fn(*self.args, **self.kwargs)21 self.event.set() #习惯上 做完了,不允许在做一次了
22 #print(self.event.is_set())
23 defadd(x, y):24 print(x +y)25
26 t = Timer(2, add,(4, 5) )27 t.start()28 t.cancel()29
30 print('--------------------------------')31 print('main thread exit')32 add(5, 6)
View Code
结果:
1 --------------------------------
2 main thread exit3 11
4
5 Process finished with exit code 0
View Code
3、Lock
锁,凡是存在共享资源争抢的地方都可以使用锁,从而保证只有一个使用这可以完全使用这个资源。
Lock,锁,一旦线程获得锁,其他试图获取锁的线程将被阻塞。
名称
含义
acquire(blocking=True, timeout=-1)
默认阻塞,阻塞可以设置超时时间,非阻塞时,timeout禁止设置,成功获取锁,返回True,否则返回Fasle
release()
释放锁,可以从任何线程调用释放,已上的锁,会被重置为unlock未上锁的锁上调用,抛RuntimeError异常
测试:需求:订单生产1000个杯子,组织10个工人生产。
1、非锁模式:
1 importthreading2 from threading importThread , Lock3 importlogging4 importtime5
6 FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
7 logging.basicConfig(format=FORMAT,level=logging.INFO)8
9 cups =[]10
11 def worker(count=10):12 logging.info("I'm workin")13 while len(cups)
<
<
<