All*_*hek 1 python queue multithreading
我在python文档中读到Queue.Queue()是一种在不同线程之间传递变量的安全方法.我真的不知道多线程存在安全问题.对于我的应用程序,我需要使用可以从多个不同线程访问的变量开发多个对象.现在我只是让线程直接访问对象变量.我不会在这里显示我的代码,因为它的方式太多了,但这里有一个例子来展示我正在做的事情.
from threading import Thread
import time
import random
class switch:
def __init__(self,id):
self.id=id
self.is_on = False
def self.toggle():
self.is_on = not self.is_on
switches = []
for i in range(5):
switches[i] = switch(i)
def record_switch():
switch_record = {}
while True:
time.sleep(10)
current = {}
current['time'] = time.srftime(time.time())
for i in switches:
current[i.id] = i.is_on
switch_record.update(current)
def toggle_switch():
while True:
time.sleep(random.random()*100)
for i in switches:
i.toggle()
toggle = Thread(target=toggle_switch(), args = ())
record = Thread(target=record_switch(), args = ())
toggle.start()
record.start()
Run Code Online (Sandbox Code Playgroud)
据我所知,队列对象只能用于放置和获取值,这显然不适用于我.我在这里"安全"吗?如果没有,我该如何编程,以便我可以安全地从多个不同的线程访问变量?
每当你有线程修改其他线程可以看到的值时,你就会遇到安全问题.担心的是,当另一个线程正在修改它时,线程将尝试修改一个值,该线程具有风险和未定义的行为.所以不,你的切换切换代码是不安全的.
重要的是要知道改变变量的值不能保证是原子的.如果某个操作是原子操作,则意味着操作将始终在一个不间断的步骤中发生.(这与数据库定义略有不同.)更改变量值(尤其是列表值)通常可以在处理器级别上执行多个步骤.当您使用线程时,所有这些步骤都不能保证在另一个线程开始工作之前一次完成.x当线程B突然接管时,线程A完全有可能在改变变量的中途.然后,如果线程B尝试读取变量x,它将不会找到正确的值.更糟糕的是,如果线程B尝试修改变量,x而线程A在做同样的事情的过程中,可能会发生不好的事情.每当你有一个值可以某种方式改变的变量时,所有对它的访问都需要成为线程安全的.
如果要修改变量而不是传递消息,则应该使用Lock对象.
在您的情况下,您Lock在顶部有一个全局对象:
from threading import Lock
switch_lock = Lock()
Run Code Online (Sandbox Code Playgroud)
然后,您将使用acquire和release函数包围关键代码段.
for i in switches:
switch_lock.acquire()
current[i.id] = i.is_on
switch_lock.release()
for i in switches:
switch_lock.acquire()
i.toggle()
switch_lock.release()
Run Code Online (Sandbox Code Playgroud)
只有一个线程可能一次获得一个锁(无论如何这种锁).当任何其他线程尝试时,它们将被阻止并等待锁再次释放.因此,通过在代码的关键部分放置锁定,您可以使多个线程无法随时查看或修改给定的开关.你可以把它放在你希望一次保留为一个线程的任何代码中.
编辑:正如马蒂诺指出的那样,with如果您使用的是具有它的Python版本,则锁与语句很好地集成在一起.如果发生异常,这具有自动解锁的额外好处.所以不是上面acquire和release系统,你可以这样做:
for i in switches:
with switch_lock:
i.toggle()
Run Code Online (Sandbox Code Playgroud)