簡體   English   中英

從函數返回的生成器過早完成

[英]Generator returned from function completes prematurely

我有以下代碼來復用阻塞生成器:

import datetime
import time
import queue
import threading


def blocking1():
    while True:
        time.sleep(1)
        result = "Block1: {}".format(datetime.datetime.now())
        yield result


def blocking2():
    while True:
        time.sleep(2)
        result = "Block2: {}".format(datetime.datetime.now())
        yield result


def multiplex(generators):
    if len(generators) == 1:
        return generators[0]
    elif len(generators) > 1:
        q = queue.Queue()

        def run_one(src):
            for e in src: q.put(e)

        def run_all():
            threads = []
            for src in generators:
                t = threading.Thread(target=run_one, args=(src,))
                t.start()
                threads.append(t)
            for t in threads: t.join()
            q.put(StopIteration)

        threading.Thread(target=run_all).start()
        while True:
            e = q.get()
            if e is StopIteration:
                return
            yield e
    else:
        return []


if __name__ == "__main__":
    # tasks = [("map1: {}".format(e) for e in blocking1()), ("map2: {}".format(e) for e in blocking2())]
    tasks = [("map1: {}".format(e) for e in blocking1())]
    for e in multiplex(tasks):
        print(e)


我想聰明一點,如果只有一個生成器,不要進行任何線程生成。 只需返回這個單一的生成器(在所有類型仍然匹配之后)

然而,它不是那樣工作的。
程序立即終止(就像這是空生成器)

有趣的是以下作品(顯示了map1...輸出):

import datetime
import time
import queue
import threading


def blocking1():
    while True:
        time.sleep(1)
        result = "Block1: {}".format(datetime.datetime.now())
        yield result


def blocking2():
    while True:
        time.sleep(2)
        result = "Block2: {}".format(datetime.datetime.now())
        yield result


def multiplex(generators):
    if len(generators) == 1:
        return generators[0]
    else:
        return []


if __name__ == "__main__":
    # tasks = [("map1: {}".format(e) for e in blocking1()), ("map2: {}".format(e) for e in blocking2())]
    tasks = [("map1: {}".format(e) for e in blocking1())]
    for e in multiplex(tasks):
        print(e)

區別僅在於刪除了elif部分...

有人可以幫我理解發生了什么嗎? 我正在使用 Python 3.5.3

您不能(有用地)從在其主體中的任何地方也執行yield的函數返回值(即使returnyield出現在永遠不會在函數的同一執行期間運行的單獨代碼塊中)。 如果您在函數的任何地方都有一個yield ,那么您正在創建一個生成器函數而不是一個普通的函數。

一個很好的解決方法是,如果您只獲得一個生成器, yield from您的單獨生成器中產生:

def multiplex(generators):
    if len(generators) == 1:
        yield from generators[0] # because this is a generator function, we need to yield here
    elif len(generators) > 1:
        ... # there's a yield in here causing the whole thing to be a generator function!

問題是您要返回一個生成器,而不是對其進行迭代。

代替

return generators[0]

yield from generators[0]

暫無
暫無

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

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