账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    协程中的委派生成器如何停止循环?
    36
    0

    本人最近在学习Python中的协程知识。在感叹yield from构造的委派生成器能够连通子生成器和待处理数据的同时,遇到一处细节苦思不解,下面详述我的问题。

    问题描述:
    在下面的实例中,我们需要利用委派生成器的知识将某班级的男女生身高和体重分别计算平均值并输出。下面的代码是可以算出正确结果的。

    但是我不理解,委派生成器(就是averager())在每次传输给子生成器数据的并接受子生成器反馈的过程中,对应的while True循环是如何停止并进入新一轮平均值的计算的呢?是因为子生成器break的影响吗?

    希望明白的前辈帮忙指点,感激不尽!!!

    from collections import namedtuple
    
    Result=namedtuple('Result','average number')
    
    def subaverager():
        total = 0.0
        number = 0
        average = None
        while True:
            term = yield
            if term is None:
                break
            total += term
            number += 1
            average=total/number
        return Result(average,number)
    
    def averager(results,key):
        while True:
            results[key]=yield from subaverager()
    
    def main(grouper):
        results={}
        for key,group in grouper.items():
            term = averager(results,key)
            next(term)
            for value in group:
                term.send(value)
            term.send(None)
        result(results)
        
    def result(results):
        for key,value in results.items():
            gender,unit=key.split(';')
            print('{} {} averaging {:.2f} {}.'.format(
                value.number,gender,value.average,unit))
    
    data = {
    'girls;kg':
    [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
    'girls;m':
    [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
    'boys;kg':
    [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
    'boys;m':
    [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
    }
    
    if __name__=='__main__':
        main(data)

    输出如下:

    10 girls averaging 42.04 kg.
    10 girls averaging 1.43 m.
    9 boys averaging 40.42 kg.
    9 boys averaging 1.39 m.
    0
    打赏
    收藏
    点击回答
        全部回答
    • 0
    • 洅回首ㄨ恍然如梦 普通会员 1楼

      在协程中,委派生成器通常用于生成多个协程,每个协程负责处理一部分特定的任务。当一个协程需要停止执行时,可以使用协程的yield关键字来暂停当前协程的执行,然后继续在其他协程中执行。以下是一个简单的示例,说明如何在协程中停止委派生成器的循环:

      ```python import concurrent.futures

      def create_tasks(num_tasks): tasks = [] for _ in range(num_tasks): task = f"yield a task" tasks.append(task) return tasks

      def main(): with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: tasks = executor.map(create_tasks, range(5)) for task in tasks: print(task)

      if name == "main": main() ```

      在这个示例中,create_tasks函数用于生成并返回一组任务。然后,main函数使用concurrent.futures.ThreadPoolExecutor创建一个最大工作量为2的协程池,其中包含5个协程。每个协程都会调用create_tasks函数,并将任务的名称作为参数传递给它。当所有的任务都被生成后,main函数使用executor.map函数将这些任务与create_tasks函数生成的任务序列一起提交给协程池。由于每个协程的yield关键字都会暂停当前协程的执行,因此当main函数完成后,协程池将自动停止执行所有协程。

      main函数中,我们使用一个for循环遍历tasks列表,打印出每个任务的名称。这是因为每个任务被生成时,都会立即执行并打印出任务名称,这与传统的协程循环完全不同,因为传统的协程循环是同步的,每次循环都会暂停当前协程的执行,等待其他协程完成。

      注意,停止协程的循环是异步的,因此在实际应用中,你可能需要考虑如何在协程暂停时处理回调函数,以确保它们在协程池停止执行后仍然能够正确地工作。在这种情况下,你可能需要使用事件循环或其他同步机制来协调协程的执行和回调函数的处理。

    更多回答
    网站公告
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部