如何在Python中的线程之间安全地传递变量值(how to safely pass a variables value between threads in python)

编程入门 行业动态 更新时间:2024-10-10 10:25:00
如何在Python中的线程之间安全地传递变量值(how to safely pass a variables value between threads in python)

我阅读了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()

据我所知,队列对象只能用于放置和获取值,这显然不适合我。 我在这里“安全”吗? 如果没有,我该如何编程,以便我可以安全地从多个不同的线程访问变量?

I read on the python documentation that Queue.Queue() is a safe way of passing variables between different threads. I didn't really know that there was a safety issue with multithreading. For my application, I need to develop multiple objects with variables that can be accessed from multiple different threads. Right now I just have the threads accessing the object variables directly. I wont show my code here because there's way too much of it, but here is an example to demonstrate what I'm doing.

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()

So as I understand, the queue object can be used only to put and get values, which clearly won't work for me. Is what I have here "safe"? If not, how can I program this so that I can safely access a variable from multiple different threads?

最满意答案

只要你有线程修改其他线程可以看到的值,那么你将会遇到安全问题。 令人担心的是,当另一个线程正在修改它时,线程会尝试修改一个值,这具有风险和未定义的行为。 所以不,你的切换代码是不安全的。

重要的是要知道,改变变量的值并不能保证是原子的 。 如果一个行动是原子的,那就意味着行动总是会在一个不间断的步骤中发生。 (这与数据库定义略有不同。)更改变量值,特别是列表值,通常可能需要处理器级别的多个步骤。 当你使用线程时,所有这些步骤不能保证在另一个线程开始工作之前一次全部发生。 当线程B突然接管时,线程A完全有可能通过更改变量x一半。 然后,如果线程B试图读取变量x ,它不会找到一个正确的值。 更糟糕的是,如果线程B尝试修改变量x而线程A通过做同样的事情,则可能会发生坏事。 每当你有一个变量的值可能以某种方式改变时,所有对它的访问都需要被设置为线程安全的。

如果你修改变量而不是传递消息,你应该使用一个Lock对象。

就你而言,你会在顶部有一个全局的Lock对象:

from threading import Lock switch_lock = Lock()

然后,您将使用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()

只有一个线程可能会一次获得一个锁(无论如何,这种锁)。 当其他线程尝试时,它们将被阻塞并等待锁再次变为空闲状态。 因此,通过在代码的关键部分添加锁定,您可以让多个线程无法随时查看或修改给定的开关。 您可以将此代码放在您想要一次保留为一个线程的独占代码中。

编辑:正如martineau指出的那样,如果你使用的是Python版本,那么锁定与with语句完美集成。 如果发生异常,这还具有自动解锁的额外好处。 因此,而不是上述acquire和release系统,你可以这样做:

for i in switches: with switch_lock: i.toggle()

Whenever you have threads modifying a value other threads can see, then you are going to have safety issues. The worry is that a thread will try to modify a value when another thread is in the middle of modifying it, which has risky and undefined behavior. So no, your switch-toggling code is not safe.

The important thing to know is that changing the value of a variable is not guaranteed to be atomic. If an action is atomic, it means that action will always happen in one uninterrupted step. (This differs very slightly from the database definition.) Changing a variable value, especially a list value, can often times take multiple steps on the processor level. When you are working with threads, all of those steps are not guaranteed to happen all at once, before another thread starts working. It's entirely possible that thread A will be halfway through changing variable x when thread B suddenly takes over. Then if thread B tries to read variable x, it's not going to find a correct value. Even worse, if thread B tries to modify variable x while thread A is halfway through doing the same thing, bad things can happen. Whenever you have a variable whose value can change somehow, all accesses to it need to be made thread-safe.

If you're modifying variables instead of passing messages, you should be using aLockobject.

In your case, you'd have a global Lock object at the top:

from threading import Lock switch_lock = Lock()

Then you would surround the critical piece of code with the acquire and release functions.

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()

Only one thread may ever acquire a lock at a time (this kind of lock, anyway). When any of the other threads try, they'll be blocked and wait for the lock to become free again. So by putting locks around critical sections of code, you make it impossible for more than one thread to look at, or modify, a given switch at any time. You can put this around any bit of code you want to be kept exclusive to one thread at a time.

EDIT: as martineau pointed out, locks are integrated well with the with statement, if you're using a version of Python that has it. This has the added benefit of automatically unlocking if an exception happens. So instead of the above acquire and release system, you can just do this:

for i in switches: with switch_lock: i.toggle()

更多推荐

本文发布于:2023-08-02 09:35:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1372744.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   变量值   如何在   Python   safely

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!