如何异步非阻塞调度python中触发的任务或事件?

How to asynchronously non-block schedule task or event triggered in python?

我已经写了我的问题的示例代码。输入消息被分成固定的块,并使用有意的随机延迟进行混合。但是,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()

sleep 确实会阻塞其 运行ning 线程。

可以通过使用 gevent. Gevent can also patch time.sleep and make it non-blocking and also has its own non-blocking sleep. It can also patch the entire python standard library to make it non-blocking - socket, time, threading etc, see 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 绑定任务不能 运行 在 greenlets 中,因为它们会阻塞事件循环和所有其他 greenlets。

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

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