多线程都是在同一个进程中运行的。因此在进程中的全局变量所有线程都是可共享的。这就造成了一个问题,因为线程执行的顺序都是无序的,有可能会造成数据错误,代码如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import threading
VALUE = 0
def add_value():
global VALUE
for i in range(10000):
VALUE += 1
print('VALUE值为:', VALUE)
def main():
for x in range(2):
t = threading.Thread(target=add_value)
t.start()
if __name__ == '__main__':
main()
因此需要在修改全局变量的时候给它加个锁,改善后代码:
示例一:增加数字
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# acquire:上锁
# release:解锁
import threading
VALUE = 0
Lock = threading.Lock()
def add_value():
global VALUE
Lock.acquire()
for i in range(10000):
VALUE += 1
print('VALUE值为:', VALUE)
Lock.release()
def main():
for x in range(2):
t = threading.Thread(target=add_value)
t.start()
if __name__ == '__main__':
main()
示例二:生产者和消费者模型
模型:生产者生产 ===> 全局变量 ===> 消费者消费变量
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import threading,random,time
VALUE = 1000
Lock = threading.Lock()
class Product(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(100,500)
Lock.acquire()
VALUE += m
print('%s 生成了数字 %s ,现在数字大小为 %s ' %(threading.current_thread(),m,VALUE))
Lock.release()
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(200,600)
Lock.acquire()
if VALUE >= m:
VALUE -= m
print('%s 消费了数字 %s ,现在数字大小为 %s ' %(threading.current_thread(),m,VALUE))
else:
print('数字 %s 太小' %VALUE)
Lock.release()
time.sleep(0.5)
def main():
for x in range(3):
t = Consumer(name='消费者线程%d' %(x))
t.start()
for x in range(5):
t = Product(name='生产者线程%d' %(x))
t.start()
if __name__ == '__main__':
main()
由于上锁是一个很耗费CPU资源的行为,因此 Lock锁机制 方式不是很友好。还有一种是通过 threading.Condition
来实现。 threading.Condition
可以在没有数据的时候处于阻塞等待状态,一旦有了合适的数据,可以使用 notify 相关的函数来通知其他等待的线程。这样可以不用做一些无用的上锁和解锁的操作,提高程序的性能。,threading.Condition类似threading.Lock,可以在修改全局数据的时候进行上锁,也可以在修改完毕后进行解锁。
acquire:上锁。
release:解锁。
wait:将当前线程处于等待状态,并且会释放锁。可以被其他线程使用notify和notify_all函数唤醒。被唤醒后会继续等待上锁,上锁后继续执行下面的代码。
notify:通知某个正在等待的线程,默认是第1个等待的线程。
notify_all:通知所有正在等待的线程。notify和notify_all不会释放锁。并且需要在release之前调用
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# 生产者和消费者模型
import threading,random,time
VALUE = 1000
cLock = threading.Condition()
class Product(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(100,500)
cLock.acquire()
VALUE += m
print('%s 生成了数字 %s ,现在数字大小为 %s ' %(threading.current_thread(),m,VALUE))
cLock.notify_all() # 通知wait()
cLock.release()
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(200,600)
cLock.acquire()
if VALUE >= m:
VALUE -= m
print('%s 消费了数字 %s ,现在数字大小为 %s ' %(threading.current_thread(),m,VALUE))
else:
print('数字 %s 太小' %VALUE)
cLock.wait() # 全局值太小了,那就等待,直到通知时候再去排队
cLock.release()
time.sleep(0.5)
def main():
for x in range(3):
t = Consumer(name='消费者线程%d' %(x))
t.start()
for x in range(2):
t = Product(name='生产者线程%d' %(x))
t.start()
if __name__ == '__main__':
main()