“确定性时间”是什么意思?例如,AWS提供服务“ AWS Lambda”。由于lambda函数具有时间限制而开始的进程,此lambda函数将停止执行,并假定任务已完成但有错误。和示例任务-将数据发送到http端点。根据到http端点的网络连接或其他因素,发送数据的过程可能需要很长时间。如果我需要将相同的数据发送到多个端点,则整个处理时间将是one process time
倍endpoints amount
。这增加了lambda函数在将所有数据发送到所有端点之前将被停止的机会。
为了解决这个问题,我需要使用线程以并行方式将数据发送到不同的端点。
线程问题-无法停止启动的线程。如果http请求所花费的时间超过了lambda函数的时间限制,则lambda函数将被中止并返回错误。因此,如果需要的时间超出预期,我需要对http请求使用超时,以中止它。
如果http请求将被超时取消或端点将返回错误,则我需要将未处理的数据保存在某个位置,以免丢失数据。可以预测保存未处理数据所需的时间,因为我控制着要保存数据的存储空间。
最后一个消耗时间的部分-调度线程的过程或循环executor.submit()
。如果只有一个端点或端点数量很少,那么消耗的时间将很小。并且没有必要控制它。但是,如果我处理了许多端点,则必须考虑到这一点。
因此,全日制基本上包括:
有一个示例我可以如何使用线程来管理时间
import concurrent.futures
from functools import partial
import requests
import time
start = time.time()
def send_data(data):
host = 'http://127.0.0.1:5000/endpoint'
try:
result = requests.post(host, json=data, timeout=(0.1, 0.5))
# print('done')
if result.status_code == 200:
return {'status': 'ok'}
if result.status_code != 200:
return {'status': 'error', 'msg': result.text}
except requests.exceptions.Timeout as err:
return {'status': 'error', 'msg': 'timeout'}
def get_data(n):
return {"wait": n}
def done_cb(a, b, future):
pass # save unprocessed data
def main():
executor = concurrent.futures.ThreadPoolExecutor()
futures = []
max_time = 0.5
for i in range(1):
future = executor.submit(send_data, *[{"wait": 10}])
future.add_done_callback(partial(done_cb, 2, 3))
futures.append(future)
if time.time() - s_time > max_time:
print('stopping creating new threads')
# save unprocessed data
break
try:
for item in concurrent.futures.as_completed(futures, timeout=1):
item.result()
except concurrent.futures.TimeoutError as err:
pass
我在考虑如何使用asyncio
库而不是线程来执行相同的操作。
import asyncio
import time
from functools import partial
import requests
start = time.time()
def send_data(data):
...
def get_data(n):
return {"wait": n}
def done_callback(a,b, future):
pass # save unprocessed data
def main(loop):
max_time = 0.5
futures = []
start_appending = time.time()
for i in range(1):
event_data = get_data(1)
future = (loop.run_in_executor(None, send_data, event_data))
future.add_done_callback(partial(done_callback, 2, 3))
futures.append(future)
if time.time() - s_time > max_time:
print('stopping creating new futures')
# save unprocessed data
break
finished, unfinished = loop.run_until_complete(
asyncio.wait(futures, timeout=1)
)
_loop = asyncio.get_event_loop()
result = main(_loop)
功能send_data()
与以前的代码相同。
因为请求库不是异步代码,所以我使用run_in_executor()
创建将来的对象。我遇到的主要问题是,done_callback()
在线程启动但执行者完成任务时未执行。但是只有在asyncio.wait()
表达式会“处理”期货时。
基本上,我在寻找开始执行异步的未来的方式,例如ThreadPoolExecutor
开始执行线程,而不是等待asyncio.wait()
表达式调用done_callback()
。如果您还有其他想法,如何编写可与线程或协程配合使用并在确定时间内完成的python代码。请分享,我将很高兴阅读它们。
还有其他问题。如果线程或将来完成了工作,它可以返回结果,我可以在done_callback()
中使用该结果,例如,根据结果返回的ID从队列中删除消息。但是,如果线程或将来被取消,我将没有结果。而且我必须使用functools.partial()
传递done_callback其他数据,这可以帮助我了解此回调被调用了哪些数据。如果传递的数据很小,这不是问题。如果数据很大,我需要将数据放入array / list / dictionary,然后仅将回调传递给数组的索引,或者将“完整数据:放入回调”中。
我能以某种方式访问从done_callback()
传递到future / thread的变量,该变量是在取消的future / thread上触发的吗?
答案 0 :(得分:0)
您可以使用asyncio.wait_for
等待将来(或与asyncio.gather
组合使用的将来),并在超时的情况下取消它们。与线程不同,asyncio支持取消,因此您可以随时取消任务,并且它将在它进行的第一个阻塞调用(通常是网络调用)中被取消。
请注意,要使其正常工作,您应该对HTTP使用aiohttp
之类的异步库。尝试使用requests
将run_in_executor
与asyncio结合起来似乎适用于简单的任务,但它不会给您带来使用asyncio的好处,例如能够产生大量任务而不会妨碍操作系统或取消的可能性。