我的要求是使用结构化的三重伪代码(实际的三重函数调用,但此处需要填写伪worker-does-work-work),因此我可以理解并尝试在同步和异步之间进行切换的良好流控制实践程序。
我要执行以下操作...
除了:我知道除了笨拙的重复重写json文件外,还有其他方法可以实现我的总体目标-但我不是在要求输入;我真的很想充分理解三重奏,以便能够将其用于 this 流程。
因此,我要同步的进程:
三重奏的新手,我有工作代码here ...,我相信它是 同步获取下一个要处理的记录(通过使用trio.Semaphore()技术) 。但是我很确定我不会 同步保存文件。
学习Go几年前,我感到自己不满意将同步和异步调用交织在一起的方法-但三重奏还不存在。预先感谢。
答案 0 :(得分:1)
这是我编写(伪)代码的方式:
async def process_file(input_file):
# load the file synchronously
with open(input_file) as fd:
data = json.load(fd)
# iterate over your dict asynchronously
async with trio.open_nursery() as nursery:
for key, sub in data.items():
if sub['updated'] is None:
sub['updated'] = 'in_progress'
nursery.start_soon(post_update, {key: sub})
# save your result json synchronously
save_file(data, input_file)
trio
向您保证,一旦退出async with
块,您生成的每个任务都已完成,因此您可以安全地保存文件,因为不会再进行更新。>
我还删除了grab_next_entry
函数,因为在我看来,该函数将在每次调用(赋予O(n!))复杂性时(递增)遍历相同的键,而您可以通过简单地简化它一次遍历您的字典(将复杂度降至O(n))
您也不需要Semaphore
,除非您想限制并行post_update
的调用次数。但是trio
也为此提供了一种内置机制,这要归功于您可以像这样使用它的CapacityLimiter:
limit = trio.CapacityLimiter(10)
async with trio.open_nursery() as nursery:
async with limit:
for x in z:
nursery.start_soon(func, x)
由于@njsmith的评论而更新
因此,为了限制并发post_update
的数量,您将像这样重写它:
async def post_update(data, limit):
async with limit:
...
然后您可以像这样重写上一个循环:
limit = trio.CapacityLimiter(10)
# iterate over your dict asynchronously
async with trio.open_nursery() as nursery:
for key, sub in data.items():
if sub['updated'] is None:
sub['updated'] = 'in_progress'
nursery.start_soon(post_update, {key: sub}, limit)
这样,我们为数据字典中的 n 条目生成 n 个任务,但是如果同时运行的任务超过10个,那么额外的任务将必须等待释放限制(在async with limit
块的末尾)。
答案 1 :(得分:1)
此代码使用通道多路复用往返工作池的请求。我发现additional requirement(在您的代码注释中)限制了响应后速率,因此read_entries
在每个send
之后都处于休眠状态。
from random import random
import time, asks, trio
snd_input, rcv_input = trio.open_memory_channel(0)
snd_output, rcv_output = trio.open_memory_channel(0)
async def read_entries():
async with snd_input:
for key_entry in range(10):
print("reading", key_entry)
await snd_input.send(key_entry)
await trio.sleep(1)
async def work(n):
async for key_entry in rcv_input:
print(f"w{n} {time.monotonic()} posting", key_entry)
r = await asks.post(f"https://httpbin.org/delay/{5 * random()}")
await snd_output.send((r.status_code, key_entry))
async def save_entries():
async for entry in rcv_output:
print("saving", entry)
async def main():
async with trio.open_nursery() as nursery:
nursery.start_soon(read_entries)
nursery.start_soon(save_entries)
async with snd_output:
async with trio.open_nursery() as workers:
for n in range(3):
workers.start_soon(work, n)
trio.run(main)