【问题标题】:How to asynchronously non-block schedule task or event triggered in python?如何在python中异步非阻塞调度任务或事件?
【发布时间】:2017-11-19 10:11:41
【问题描述】:

我已经编写了我的问题的示例代码。输入消息被分成固定的块,并使用有意的随机延迟进行混合。但是,sleep() 处于阻塞状态,不会运行下一个任务。这可以在单线程上实现还是我必须求助于多线程?

from random import randint
from time import sleep

def delay_message(split_message, delay):
    #sleep(delay) #this blocks
    print("Shuffled message: {} and time: {}". format(split_message, delay)) 

def main():
    message = raw_input('Input: ')

    #padding
    difference = len(message) % 5
    message=message.ljust(len(message)+5-difference, "0")

    for i in range(0, len(message), 5):
        delay = randint(0, 5)
        split_message = message[i:i+5]
        delay_message(split_message, delay)

if __name__ == "__main__":
    main()

【问题讨论】:

  • 看看asyncio。如果它真的只是你需要的非阻塞睡眠,那可能会有所帮助。

标签: python scheduled-tasks scheduler


【解决方案1】:

sleep 确实会阻塞它正在运行的线程。

可以使用gevent 之类的库使其成为非阻塞。 Gevent 还可以对time.sleep 进行修补,使其成为非阻塞状态,并且具有自己的非阻塞睡眠状态。它还可以修补整个 python 标准库以使其成为非阻塞的 - 套接字、时间、线程等,请参阅documentation

上面的例子可以像这样与 gevent 协同并发:

from random import randint
from gevent import sleep, spawn, joinall

def delay_message(split_message, delay):
    # Gevent's sleep yields the event loop for
    # duration of delay rather than blocking the running thread
    sleep(delay)
    print("Shuffled message: {} and time: {}". format(split_message, delay)) 

def main():
    message = raw_input('Input: ')

    #padding
    difference = len(message) % 5
    message=message.ljust(len(message)+5-difference, "0")

    greenlets = []
    # This will create len(message)/5 number of greenlets,
    # which corresponds to the concurrency level.
    # Greenlets all run under one thread so there is no CPU
    # overhead here.
    for i in range(0, len(message), 5):
        delay = randint(0, 5)
        split_message = message[i:i+5]
        greenlets.append(spawn(delay_message, split_message, delay))
    # Wait for all greenlets to complete, raise any exceptions
    joinall(greenlets, raise_error=True)

if __name__ == "__main__":
    main()

限制是 CPU 绑定的任务不能在 greenlet 中运行,因为它们会阻塞事件循环和所有其他 greenlet。

只要在 greenlets 中运行的内容是 I/O 绑定的,例如在套接字或生成器中传递消息,其他 greenlets 等,greenlets 都是合适的。对于 CPU 密集型任务,请使用本机线程或多个进程。

还有其他选择,例如 asyncio(仅限 Py3)。 Gevent 与 Py2 和 3 兼容,具有非常高的性能,由本机代码扩展支持。

【讨论】:

  • 谢谢,这很有趣。受 CPU 限制,您的意思是 delay_message 是否正在执行繁重的操作?或者你能给我举个例子来说明你的意思吗
  • CPU 绑定任务是任何在 CPU 上执行代码时被阻塞的任务。例如音频/视频编码和解码、图像处理等,基本上任何涉及在 CPU 上运行的代码。 I/O 绑定任务将是通过网络读取/写入流、网络请求处理、磁盘 I/O 等。网络也可以由线程处理,但这意味着大量 CPU 开销(增加 CPU 使用率,降低最大并发性)实际上不受 CPU 限制。为此,协作式多任务处理(也称为异步 I/O)更适合。
  • 这很有意义,谢谢。 Gevent 没有usleep() or nanosleep() 的高精度。有没有办法用当前方法处理这个问题?或者你能建议我可以研究的另一种方式
  • sleep(0.01) 和亚秒级睡眠的类似工作正常。和其他任何基于计时器的东西一样准确。
猜你喜欢
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 2019-01-24
  • 1970-01-01
  • 2011-09-16
  • 2018-04-06
相关资源
最近更新 更多