gpt4 book ai didi

python - 类成员定期更新的线程

转载 作者:行者123 更新时间:2023-12-01 03:42:52 25 4
gpt4 key购买 nike

当 Python 中的类成员仍在被类中的其他方法使用时,有什么方法可以更新该成员?

我希望类的其余部分继续使用旧版本的成员进行处理,直到其完全更新,然后在更新完成后将所有处理切换到新版本。

这是一个玩具示例来说明我的用例,其中 self.numbers 是需要使用 updateNumbers() 中的逻辑安全地线程化定期更新的类成员,我希望通过 runCounter() 以非阻塞方式调用它。

from time import sleep, time

class SimpleUpdater(object):
def __init__(self):
self.i = 5
self.numbers = list(range(self.i))
self.lastUpdate = time()
self.updateDelta = 10

def timePast(self):
now = time()
delta = self.lastUpdate - now
return (delta > self.updateDelta)

def updateNumbers(self):
print('Starting Update', flush=True)
self.numbers = list(range(self.i))
# artificial calculation time
sleep(2)
print('Done Updating', flush=True)

def runCounter(self):
for j in self.numbers:
print(j, flush=True)
sleep(0.5)
self.i += 1
if self.timePast:
## Spin off this calculation!! (and safely transfer the new value)
self.updateNumbers()

if __name__ == '__main__':
S = SimpleUpdater()
while True:
S.runCounter()

所需的行为是,如果在循环中迭代 self.numbers,则应在切换到新版本之前使用旧版本完成循环。

最佳答案

您可以为每次调用 updateNumbers 创建一个新线程,但执行此类操作的更常见方法是让 1 个线程在后台运行无限循环。您应该使用该无限循环编写一个方法或函数,并且该方法/函数将作为后台线程的目标。这种线程通常是守护进程,但并非必须如此。我修改了您的代码以展示如何完成此操作(我还修复了示例代码中的一些小错误)。

from time import sleep, time
import threading


class Numbers(object):
def __init__(self, numbers):
self.data = numbers
self.lastUpdate = time()


class SimpleUpdater(object):
def __init__(self):
self.i = 5
self.updateDelta = 5
self.numbers = Numbers(list(range(self.i)))
self._startUpdateThread()

def _startUpdateThread(self):
# Only call this function once
update_thread = threading.Thread(target=self._updateLoop)
update_thread.daemon = True
update_thread.start()

def _updateLoop(self):
print("Staring Update Thread")
while True:
self.updateNumbers()
sleep(.001)

def updateNumbers(self):
numbers = self.numbers
delta = time() - numbers.lastUpdate
if delta < self.updateDelta:
return
print('Starting Update')
# artificial calculation time
sleep(4)
numbers = Numbers(list(range(self.i)))
self.numbers = numbers
print('Done Updating')

def runCounter(self):
# Take self.numbers once, then only use local `numbers`.
numbers = self.numbers
for j in numbers.data:
print(j)
sleep(0.5)
# do more with numbers
self.i += 1


if __name__ == '__main__':
S = SimpleUpdater()
while True:
S.runCounter()

请注意,我没有使用任何锁:)。我可以在不使用任何锁的情况下逃脱,因为我只使用原子操作访问 SimpleUpdater 类的 numbers 属性,在本例中只是简单的赋值。每次对 self.numbers 的赋值都会将一个新的 Numbers 对象与该属性相关联。每次访问该属性时,您都应该期望获得不同的对象,但是如果您在方法的开头获取对该对象的本地引用,即 numbers = self.numbers, numbers 将始终引用同一个对象(直到它在方法结束时超出范围),即使后台线程更新了 self.numbers

我创建 Numbers 类的原因是,我可以在单个(原子)赋值(数字列表和 LastUpdated 值)中获取和设置所有“ volatile ”成员。我知道需要跟踪的内容很多,老实说,仅使用锁可能更聪明、更安全:),但我也想向您展示这个选项。

关于python - 类成员定期更新的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39282197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com