zoukankan      html  css  js  c++  java
  • chapter9_2 管道与过滤器

      一个关于协同程序的经典示例就是“生产者-消费者”的问题。

    一个不断产生值,一个不断消费这些值。比如:

    function producer()
        while true do
            local x = io.read()         --produce new value
            send(x)                        --send it to consumer
        end
    end
    
    function consumer()
        while true do
            local x = receive()        --receive value from producer
            io.write(x,"
    ")            --consumer it
        end
    end

    如何将send和receive匹配起来,这是一个典型的“谁有主循环”的问题。由于两则都有一个主循环,并且都将对方视为一个可调用的服务。

    协同程序被称为一种匹配生产者和消费者的理想工具,一对resume-yield完全一改典型的调用者与被调用者之间的关系。

    当一个协同程序调用yield时,它不是进入一个新的函数,而是从一个resume调用中返回。

    同样对于resume,也不是启动一个新函数,而是从一次yield调用中返回。

    两者都认为自己是主动方,对方是被动。

    receive唤醒生产者,使它产生一个新值。而send则产生一个新值返还给消费者:

    function receive()
        local status,value = coroutine.resume(producer)
        return value
    end
    
    function send(x)
        coroutine.yield(x)
    end

    因此,生产者现在一定是一个协同程序

    producer = coroutine.create( function ()
            while true do
            local x = io.read()        --产生新值
                send(x)
            end
        end)

    在这种设计中,程序通过调用消费者来启动,当消费者需要一个新值时,唤醒生产者。

    生产者返回一个新值后停止运行,并等待消费者的再次唤醒。这种设计称为“消费者驱动(consumer-driven)”。

    还有一种就是使用“生产者驱动”设计,消费者是一个协同程序。

    过滤器

      过滤器是一种位于生产者和消费者之间的处理功能,可用于对数据的一些变换。

    过滤器既是一个消费者又是一个生产者,它唤醒一个生产者促使其产生新值,又将变换后的值传递给消费者。

    例如,在上面的代码中添加一个过滤器,在每行起始处插一个行号:

    function receive(prod)
        local status,value = coroutine.resume(prod)
        return value
    end
    
    function send(x)
        coroutine.yield(x)
    end
    
    function producer()
        return coroutine.create(function ()
            while true do
                local x = io.read()        --产生一个新值
                send(x)
            end
        end)
    end
    
    function filter(prod)
        return coroutine.create(function ()
            for line = 1,math.huge do
                local x = receive(prod)    --获得一个新值
                x = string.format("%5d %s",line,x)
                send(x)                    -- send it to consumer
            end
         end)
    end
    
    function consumer(prod)
        while true do
            local x = receive(prod)     --获得一个新值
            io.write(x,"
    ")            --消费一个新值
        end
    end

    接下来运行代码,然后启动消费者:

    p = producer ()
    f = filter(p)
    consumer(f)
    
    --或者更简单
    consumer(filter(producer()))

    在pipe中每个任务都在各自独立的进程中运行,而在协同程序中每项任务都在各自独立的协同程序中运行。

    pipe在消费者与生产者之间提供一个缓冲器,因此它们的运行速度允许存在一定差异。但是,在pipe中进程间切换代价很高。

    而在协同程序中,切换代价小得多(差不多等于函数调用)。

  • 相关阅读:
    Shell脚本中$0、$#、$@等的意义
    shell脚本中常见的一些特殊符号和作用详解
    shell脚本中的反引号,单引号,双引号与反斜杠
    Shell中反引号(`)与$()用法的区别
    自己在linux上编译、链接、动态库和静态库的学习笔记
    让ie6 7 8 9支持原生html5 websocket
    解决浏览器不兼容websocket
    WebSocket兼容到低版本浏览器
    UART和RS232/RS485的关系,RS232与RS485编程
    TTL和RS232之间的详细对比
  • 原文地址:https://www.cnblogs.com/daiker/p/5821377.html
Copyright © 2011-2022 走看看