如何在单独的线程中安全地修改类属性并从中返回它们?

问题描述 投票:0回答:1

我已经定义了一个类Test,其中一个方法,updater,在一个单独的线程中运行并不断更新属性,steps。我希望有关安全修改属性以及在其他线程中安全访问该属性的一些明确建议。

下面是一些满足我要求的工作代码,使here建议自由使用线程锁。我已经在两个线程中部署了锁,并且获取和设置了方法,因为属性steps上的操作都是非原子的(或者很可能是在我完成的代码中)。

from threading import Thread, Lock
from time import sleep


class Test:
    def __init__(self):
        self.lock = Lock()
        self.steps = 5
        self.thread = Thread(target=self.updater)
        self.threadRun = True
        self.thread.start()

    def updater(self):
        while self.threadRun:
            with self.lock:
                self.steps += 1
            sleep(0.001)
        print('Thread stopped')

    def get_steps(self):
        with self.lock:
            return self.steps

    def set_steps(self, steps):
        with self.lock:
            self.steps = steps

我知道直接访问实例属性比使用getter和setter方法更受欢迎:

a = Test()
steps = a.steps
a.steps = 5

而不是:

a = Test()
steps = a.get_steps()
a.set_steps(5)

但我在这里使用它们所以我可以包括锁。我不确定在这种情况下直接访问属性的原子性,因此可能能够避免锁定,但有人可以确认是否是这种情况?如果我仍然需要使用锁,并为我想要访问的每个属性使用getter和setter方法,那么当我扩展到多个属性时,如何在类中部署装饰器以使其更加智能?我期待这样的事情:

from threading import Thread, Lock
from time import sleep


class Test:
    def __init__(self):
        self.lock = Lock()
        self.steps = 5
        self.thread = Thread(target=self.updater)
        self.threadRun = True
        self.thread.start()

    def updater(self):
        while self.threadRun:
            with self.lock:
                self.steps += 1
            sleep(0.001)
        print('Thread stopped')

    def locker(self, func):
        with self.lock:
            return func

    @locker
    def get_steps(self):
        return self.steps

    @locker
    def set_steps(self, steps):
        self.steps = steps

但是在这一点上,我在类和装饰器之间的参数处理方面的技巧很短,我得到:

TypeError: locker() missing 1 required positional argument: 'func'

一些见解是here,但根据对解决方案的第一个评论,我需要正确处理参数。我想我可以把锁定器函数放在类之外,但我希望在类中包含它以保持整洁 - 我不会在其他地方使用它。这里有什么优雅的解决方案?

python oop python-multithreading python-decorators
1个回答
0
投票

好的,在this question的帮助下,我有一个可行的解决方案:

from threading import Thread, Lock
import time


class Blah():
    def __init__(self):
        self.lock = Lock()
        self.a = 0
        self.thread = Thread(target=self.updater)
        self.threadRun = True
        self.thread.start()

    def locker(func):
        def magic(self, *args):
            with self.lock:
                print('locked')
                return func(self, *args)
        return magic

    def updater(self):
        t_start = time.time()
        while self.threadRun and time.time() - t_start <= 20:
            self.a += 1
            time.sleep(2)
        print('Thread stopped')

    @property
    @locker
    def a(self):
        return self._a

    @a.setter
    @locker
    def a(self, val):
        self._a = val

我现在正试图将这种方法应用于许多实例属性,而不仅仅是a,我正在寻找一种pythonic /动态方法来做到这一点,而不是每个都有两个离散的代码块(@property@attr.setter)。理想情况下,我会初始化__init__构造函数中的每个属性,这将分配初始值并设置@property@attr.setter方法,适当地用@locker包装。任何人都可以建议如何做到这一点?

© www.soinside.com 2019 - 2024. All rights reserved.