lua协程 1970-01-01 00:00

概念

协程并不是Lua独有的东西,很有语言实现了协程,比如Go、Python等。协程是一种类似于线程的东西,我们可以将它理解为用户态的线程,协程的调度是由开发者控制的,一个线程只能同时运行一个协程,非并行执行,线程是由操作系统调度的,如果有多核的话,是可以并行执行的。

主要函数

Lua协程几个主要函数:

coroutine.create - 创建协程

coroutine.status - 查看协程状态

coroutine.resume - 执行协程

coroutine.yield - 挂起协程

有两个需要注意的地方:

看下面的代码:

!/usr/local/bin/lua

function greet()

    a = coroutine.yield("hello,wrold")
    return a+1
end

co = coroutine.create(greet)

print(coroutine.status(co))
print("step1")
print(coroutine.resume(co,"a","b"))
print(coroutine.status(co))
print("step2")
print(coroutine.resume(co,"1"))
print(coroutine.status(co))

程序输出:

suspended  
step1  
true    hello,wrold  
suspended  
step2  
true    2.0  
dead

生产者和消费者

用协程实现一个经典的生产者和消费者: 生产者负责读取输入、消费者打印输出。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/local/bin/lua

function producer()
    return coroutine.create(function()
        while true do
            local line = io.read()
            coroutine.yield(line)
        end
    end)
end

function consumer(p)
    while true do
        local status,line = coroutine.resume(p)
        if status then
            io.write("INPUT:",line,"\n")
        else
            break
        end
    end
end

p = producer()
consumer(p)

执行:

line=1;while true; do echo "hello,world $line";sleep 1;let line=line+1; done| ./producer.lua

输出:

INPUT:hello,world 1
INPUT:hello,world 2
INPUT:hello,world 3
INPUT:hello,world 4
INPUT:hello,world 5
INPUT:hello,world 6
INPUT:hello,world 7
INPUT:hello,world 8
INPUT:hello,world 9
INPUT:hello,world 10
INPUT:hello,world 11
INPUT:hello,world 12

Python用yield实现协程和Lua很多相似的地方,下面是一个Python的实现:

import sys

def producer():

    while True:
        line = sys.stdin.readline()
        yield line

def consumer(p):
    line = p.next()
    while True:
        print "INPUT:",line,
        line = p.send('')


p = producer()
consumer(p)

相比用两个线程来模拟生产者和消费者是不是简单多了,而且还不用考虑加锁,因为整个流程都是非抢占式的:)

并发

单线程要实现并发肯定是靠非阻塞或者异步IO了。Linux上的实现有selectpoll和现在的epoll。select、poll是轮询机制、epoll是事件通知机制。

用协程模拟select来实现并发。

访问 http://httpbin.org/delay/3,这个请求响应时间为3S。

完整代码见这里协程模拟select来实现并发

看5次请求所需时间:

worker0 start....       /delay/3
worker1 start....       /delay/3
worker2 start....       /delay/3
worker3 start....       /delay/3
worker4 start....       /delay/3
worker0 done...
worker1 done...
worker2 done...
worker3 done...
worker4 done...
start at:       21:42:59
end at: 21:43:04

花费5s左右。

30次请求测试:

.....
worker27        done...
worker29        done...
worker28        done...
start at:       21:45:40
end at: 21:45:54

花费14s左右。

Python的实现