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

问题描述:

我写了一个我的问题的示例代码。输入消息被分成固定块,并使用有意的随机延迟进行混合。但是,sleep()正在阻止并且不会运行下一个任务。这是可能的单线程还是我不得不求助于多线程?如何在python中触发异步非阻塞调度任务或事件?

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() 
+0

查看['asyncio'](https://docs.python.org/3/library/asyncio.html)。如果它真的只是你需要的非阻塞睡眠,那可能会有所帮助。 –

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密集型任务不能在greenlets运行,因为它们会阻止事件循环和所有其他greenlets。

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

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

+0

谢谢,这很有趣。通过CPU绑定,你的意思是,如果delay_message执行繁重的操作?或者你可以给我一个例子,你的意思是这样的 – Anderson

+0

CPU绑定任务将是在CPU上执行代码时被阻塞的任何东西。例如音频/视频编码和解码,图像处理等,基本上涉及在CPU上运行的代码。 I/O绑定任务将通过网络读取/写入流,网络请求处理,磁盘I/O等。网络也可以由线程来处理,但这意味着很多CPU开销(CPU使用率增加,最大并发度降低)对于事实上并未受CPU限制的事情。为此,合作多任务即异步I/O更适合。 – danny

+0

这是有道理的感谢。 Gevent没有'usleep()或nanosleep()'高度的准确性。有没有办法处理这与当前的方法?或者你能否建议另一种方式,我可以研究 – Anderson