簡體   English   中英

Python - 如何使這段代碼異步?

[英]Python - How can I make this code asynchronous?

這是一些說明我的問題的代碼:

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。

如何異步我的非套接字相關的阻塞函數?

阻塞功能是一種不返回的功能,但仍會使您的進程處於空閑狀態 - 無法完成更多工作。

您要求我們使您的阻止功能無阻塞。 但是-除非你寫一個操作系統- 沒有任何阻擋功能。 您可能具有阻塞函數,因為它們調用阻塞系統調用,或者您可能具有“阻塞”的函數,因為它們執行大量計算。

如果不使基礎系統調用非阻塞,則使前一類函數無阻塞是不可能的。 根據系統調用的內容,如果不向程序添加事件循環,可能很難使其無阻塞; 您不僅需要撥打電話並且不要阻止,您還必須再次撥打電話以確定該呼叫的結果將在您可以關聯的地方發送。

這個問題的答案是一個非常長的python程序和許多不同操作系統界面的解釋以及它們如何工作,但幸運的是我已經在不同的網站上寫了這個答案; 我叫它扭曲 如果Twisted反應堆已經支持您的特定任務,那么您很幸運。 否則,只要您的任務映射到某些現有操作系統概念,您就可以擴展反應器以支持它。 實際上,這些機制中只有兩種:每個合理操作系統上的文件描述符,以及Windows上的I / O完成端口。

在另一種情況下,如果你的功能消耗了大量的CPU,因此沒有返回,它們並沒有真正阻塞; 你的過程仍在繼續,並完成工作。 有三種方法可以解決這個問題:

  • 單獨的線程
  • 單獨的過程
  • 如果你有一個事件循環,編寫一個定期產生的任務,通過以一種工作方式編寫任務,然后要求事件循環在不久的將來恢復它,以便允許其他任務運行。

在Twisted中,最后一種技術可以通過各種方式實現,但這里有一種語法上方便的技巧,可以輕松實現:

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)

您可以使用生成器進行協作式多任務處理,但您必須編寫自己的主循環,在它們之間傳遞控制。

以下是使用上面示例的(非常簡單)示例:

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)

您可以通過允許生成器生成新的生成器來進一步改進它,然后可以將其添加到任務中,但希望這個簡化的示例將給出一般的想法。

扭曲的框架不僅僅是套接字。 它具有適用於許多場景的異步適配器,包括與子進程交互。 我建議仔細看看。 它做你想做的事。

如果您不想使用完整的OS線程,您可以嘗試使用Stackless ,這是Python的一種變體,它添加了許多有趣的功能,包括“microthreads”。 您會發現許多有用的好例子

您的代碼沒有阻止。 blocking1()和它的兄弟立即返回迭代器(不阻塞),也沒有一個迭代塊(在你的情況下)。

如果你想從兩個迭代器中逐個“吃”,不要讓你的程序在繼續之前嘗試完全吃掉“blocking1()”。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM