2011-02-11 63 views
9

下面是一些代码,说明我的问题:Python - 如何使此代码异步?

def blocking1(): 
    while True: 
     yield 'first blocking function example' 

def blocking2(): 
    while True: 
     yield 'second blocking function example' 

for i in blocking1(): 
    print 'this will be shown' 

for i in blocking2(): 
    print 'this will not be shown' 

我有包含while True循环两种功能。这些将产生数据,然后我会记录在某处(最有可能,到一个SQLite数据库)。

我一直在玩弄线程和已经得到它的工作。但是,我不太喜欢它......我想要做的是使我的阻塞函数异步。例如:

def blocking1(callback): 
    while True: 
     callback('first blocking function example') 

def blocking2(callback): 
    while True: 
     callback('second blocking function example') 

def log(data): 
    print data 

blocking1(log) 
blocking2(log) 

我该如何在Python中实现这个功能?我已经看到标准库带有asyncore,这个游戏中的大名是Twisted,但这两个似乎都用于套接字IO。

如何异步我的非套接字相关的阻塞函数?

+0

`什么我想要做的是使我的阻塞功能异步`这没有任何意义。你可能希望你的函数阻塞,或者你希望它是异步的。如果你想要它异步,使用一个线程。我看不出有什么问题。 – Falmarri 2011-02-11 06:21:26

+0

我希望我的阻塞函数是非阻塞的 – dave 2011-02-11 06:25:10

+0

关于这些函数的执行是如何进行交错的,而不仅仅是相互之间,还有你运行的所有后续代码,还有很多问题需要回答。这就是操作系统的用途,以及为什么你一般都想使用一个线程来做类似的事情。 你能解释一下你不喜欢线程吗?这正是线程创建要解决的问题。 – 2011-02-11 06:30:53

回答

1

如果你不想使用完整的操作系统线程,你可以试试Stackless,这是一个Python的变种,增加了很多有趣的功能,包括“微线程”。有很多好的examples,你会发现有帮助。

9

可以使用发电机合作多任务,但你必须编写可以通过它们之间的控制自己的主循环。

下面是使用你上面的例子一(很简单的)例子:

def blocking1(): 
    while True: 
     yield 'first blocking function example' 

def blocking2(): 
    while True: 
     yield 'second blocking function example' 


tasks = [blocking1(), blocking2()] 

# Repeat until all tasks have stopped 
while tasks: 
    # Iterate through all current tasks. Use 
    # tasks[:] to copy the list because we 
    # might mutate it. 
    for t in tasks[:]: 
     try: 
      print t.next() 
     except StopIteration: 
      # If the generator stops, remove it from the task list 
      tasks.remove(t) 

您可以通过允许发电机产生新的发电机,然后可以添加到任务,进一步完善它,但希望这简单的例子将给出总体思路。

2

扭曲的框架不只是套接字。它在许多场景中都有异步适配器,包括与子进程交互。我建议仔细看看。它做你正在做的事情。

28

阻塞函数是不返回的函数,但仍留下你的进程闲置 - 无法完成更多的工作。

你要我们做闭锁功能无阻塞。但是 - 除非您正在编写操作系统 - 您的没有任何阻止功能。你可能会因为阻止系统调用而调用阻塞的函数,或者你可能因为执行大量计算而具有“阻塞”的函数。

使前者类型功能无阻塞的,而不会使基础系统调用无阻塞是不可能的。根据系统调用的内容,可能很难在不向程序添加事件循环的情况下进行非阻塞操作;您不仅需要拨打电话并阻止该呼叫,还必须再拨打一个电话才能确定该呼叫的结果将传送到您可以关联的地方。

回答这个问题是一个很长的Python程序和大量不同的操作系统界面的说明,以及它们如何工作,但幸运的是,我已经写上不同的站点的答案;我称之为Twisted。如果你的特定任务已经是supported by a Twisted reactor,那么你很幸运。否则,只要你的任务映射到一些现有的操作系​​统概念,你就可以扩展一个反应堆来支持它。实际上,这些机制中只有两个:在每个明智的操作系统上都有文件描述符,在Windows上有I/O完成端口。在另一种情况下,如果你的函数消耗了大量的CPU,因此不能返回,它们并不是真正的阻塞;你的过程仍然在徘徊,并完成工作。有三种方法来处理是:

  • 单独的线程
  • 单独的进程
  • ,如果你有一个事件循环,编写定期产生一个任务,通过这样一种方式,它写的任务一些工作,然后要求事件循环在不久的将来继续执行,以便允许其他任务运行。

在扭曲这个最后的技术可以通过多种方式来实现,但这里有一个语法方便的技巧,可以很容易:

from twisted.internet import reactor 
from twisted.internet.task import deferLater 
from twisted.internet.defer import inlineCallbacks, returnValue 

@inlineCallbacks 
def slowButSteady(): 
    result = SomeResult() 
    for something in somethingElse: 
     result.workHardForAMoment(something) 
     yield deferLater(reactor, 0, lambda : None) 
    returnValue(result) 
0

您的代码是不会阻止。 blocking1(),它是兄弟立即返回迭代器(不是阻塞),也不是一个迭代块(在你的情况下)。

如果你想从两个迭代器一个接一个“吃”,不要让你的程序尽量吃起来“blocking1()”完全,然后再继续......

for b1, b2 in zip(blocking1(), blocking2()): 
    print 'this will be shown', b1, 'and this, too', b2