比方说,我有一个电子广告牌,应该显示最新的信息,该信息每秒可能更改一次以上。广告牌的更新例程大约需要10秒钟,因此每次调用和阻止它都是不理想的。
因此,让我们将其设为异步协程,并使用>>> df = pd.merge(df, prev_identifiers, how='left', on='date')
>>> df['is_new'] = df.apply(lambda row: row['identifier'] not in row['identifier_prev'], axis=1)
>>> print(df)
date identifier value identifier_prev is_new
0 2019-12-31 a1 10 True
1 2019-12-31 a2 20 True
2 2019-12-31 a3 30 True
3 2020-01-31 a1 40 a1,a2,a3 False
4 2020-01-31 a2 50 a1,a2,a3 False
5 2020-01-31 a4 60 a1,a2,a3 True
6 2020-01-31 a5 60 a1,a2,a3 True
7 2020-02-28 a1 70 a1,a2,a4,a5 False
8 2020-02-28 a4 80 a1,a2,a4,a5 False
9 2020-02-28 a3 90 a1,a2,a4,a5 True
进行调用。这样一来,就有可能同时运行多个更新协程,甚至可能引入竞争条件,在这些条件下,最后的更新被延迟的先前更新所覆盖。
是否有一种整洁的Python方式来处理此问题?
我考虑过一个内部的未来,在调用update时,可以将其启动或等待完成,然后再调用它。但这不会再次阻止更新吗?
asyncio.ensure_future
答案 0 :(得分:1)
您可以使用带有几个布尔标志的类来管理更新。像这样:
#! python3.8
import asyncio
import random
class Updater:
def __init__(self):
self.in_process = False
self.pending = False
async def request(self):
if self.in_process:
self.pending = True
return
self.pending = False
self.in_process = True
await asyncio.sleep(2.0) # Ten seconds is too boring
self.in_process = False
print("...updated")
if self.pending:
asyncio.create_task(self.request())
async def main():
up = Updater()
while True:
seconds = random.random() * 4.0
await asyncio.sleep(seconds)
print("request")
asyncio.create_task(up.request())
asyncio.run(main())
第一个请求进入时,更新程序将运行。如果在第一个请求处理过程中出现另一个请求,它将设置“ pending”标志并返回。
在更新功能结束时,它检查是否有任何新请求挂起;如果是这样,它将重新安排自己的时间。如果没有,那一切都完成了。在这种情况下,直到main()函数发出新请求后,它才会再次运行。
实际上,“ pending”标志是一个请求队列,最大队列深度为1。多个请求被序列化,因此一次运行的请求不超过一个。它不在乎请求到达的速度是否超过其处理速度;它会处理所有可能的东西,然后丢弃其余的东西。