一,lua协程简介

协程(coroutine),意思就是协作的例程,最早由Melvin Conway在1963年提出并实现。跟主流程序语言中的线程不一样,线程属于侵入式组件,线程实现的系统称之为抢占式多任务系统,而协程实现的多任务系统成为协作式多任务系统。线程由于缺乏yield语义,所以运行过程中不可避免需要调度,休眠挂起,上下文切换等系统开销,还需要小心使用同步机制保证多线程正常运行。而协程的运行指令系列是固定的,不需要同步机制,协程之间切换也只涉及到控制权的交换,相比较线程来说是非常轻便的。不过同一时刻可以有多个线程运行,但却只能有一个协程运行。

协程具有两个非常重要的特性:

1. 私有数据在协程的间断式运行期间一直有效

2. 协程每次yield后让出控制权,下次被resume后从停止点开始继续执行

通俗的说,比较像一个带有静态数据而且具有多个进入点和返回点的函数,下面通过一个简单例子看看这个性质:

co = coroutine.create(
function(a)
print("a = "..a)
c = coroutine.yield(a+1)
print("c = "..c)
return c*2
end
)
_, b = coroutine.resume(co, 1)
print("b = "..b)
_, d = coroutine.resume(co, b )
print("d = "..d)

运行结果:

a = 1

b = 2

c = 2

d = 4

协程co中除了一般函数具有的进入点(函数入口处)和返回点(函数结尾),在yield出还有一个进入点和返回点。主程序第一次resume时将1传给参数a,运行到yield时,协程返回控制权给主程序,并通过yield的参数提供返回值,于是b=a+1,再次resume时,主程序通过参数b将数据传给co的变量c,从而从第二个入口点进入函数,最后返回值c*2传给d。

resume/yield语义实现的协程属于非对称协程,在非对称协程中,调用者和被调用者的关系是固定的,调用者通过resume将控制流转到被调用者,被调用者通过yield只能返回到调用者,而不能返回到其他协程。比如A resume B resume C, C yield只能到B,而不能到A或其他协程。

世间万物都是对立又统一的,既然存在非对称协程,当然就存在对称协程。对称协程只有一个语义可以将控制流直接转到目的协程。

非对称协程和对称协程的表达能力是一样的,lua中只实现了非对称协程,一个重要原因是lua是c实现的,非对称协程的调用与被调用关系与c的函数调用非常类似,方便lua和c的扩展编程。

二,协程实战

下面例子利用协程实现经典的生产者-消费者模型。

count = 10
productor = coroutine.create(
function ()
i = 0
while(true) do
i = i+1
coroutine.yield(i)
end
end
) consumer = coroutine.create(
function(co)
n = 1
while(n<count) do
_, v = coroutine.resume(co)
print(v)
n = n+1
end
end
) coroutine.resume(consumer, productor)

consumer启动productor,productor产生一个item后通过yield传回给consumer,然后挂起等待consumer下次resume,非常简单直观。

协程的另一个重要作用是作为迭代器,依次访问数据结构的元素。下面代码展示了先序访问二叉树的方法。

l = {
v = 1,
left = nil,
right = nil,
} r = {
v = 2,
left = nil,
right = nil,
} root = {
v = 3,
left = l,
right = r,
} preorder = function(root)
if(root == nil) then return end
coroutine.yield(root.v)
preorder(root.left)
preorder(root.right)
end preco = coroutine.create(preorder) view = function(co, root)
state, v = coroutine.resume(co, root)
if(state == false) then return end
print(v)
while(true) do
state, v = coroutine.resume(co)
if(state == false or v == nil) then return end
print(v)
end
end
view(preco, root)

对于coroutine, 这里介绍了一个非常轻量级协程的实现原理,云风通过uconext实现了类似于lua的协程库,有兴趣的同学可以研究研究。

reference:

《coroutines in C》

lua编程之协程介绍的更多相关文章

  1. python并开发编程之协程

    一 引出协成 并发的本质是:切换+保存状态 CPU在运行行一个任务时,会在两种情况下切走去执行其他任务,一是该任务发生了阻塞,二是运行该任务的时间过长 yeild可以保存状态,yeild状态保存与操作 ...

  2. python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)

    昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...

  3. {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二

    python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...

  4. 32 python 并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  5. 【python】-- 协程介绍及基本示例、协程遇到IO操作自动切换、协程(gevent)并发爬网页

    协程介绍及基本示例 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他 ...

  6. 四 python并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  7. 百万年薪python之路 -- 并发编程之 协程

    协程 一. 协程的引入 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两 ...

  8. 协程介绍, Greenlet模块,Gevent模块,Genvent之同步与异步

    昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...

  9. python并发编程之协程(实践篇)

    一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 对于单线程下,我们不可避免程序中出现io操作,但如果我们 ...

随机推荐

  1. September 11th 2017 Week 37th Monday

    I believe there is a hero in all of us. 我相信每个人心中都住着一个英雄. For every of us, there are two version with ...

  2. 18年10月31日 NOIP模拟赛

    T1.exercise 题解 数据很小直接模拟 代码 #include<iostream> #include<cstdio> #include<cmath> #in ...

  3. Subversion、TortoiseSVN、Ankhsvn+VS使用

    Subversion为版本控制软件的服务器端.VisualSVN Server 可以在Windows平台安装和管理全功能的Subversion server. TortoiseSVN为Subversi ...

  4. PAT 1001 A+B 解题报告

    PAT 1001 A+B 代码链接:传送门 题目链接:传送门 题目简述: 给定两个值a,b: 范围-1000000 <= a, b <= 1000000: 按指定格式输出a+b的结果,例: ...

  5. [CSS]关于z-index与position的一次奇异经历

    前言: 前不久,同事S遇到了一个关于position和z-index的问题. 他折腾了一天没搞定,群发了邮件寻求帮助, 我一开始以为很简单,就主动说帮忙,简单尝试之后,才发现貌似没那么简单. 问题主要 ...

  6. 3种web会话管理方式

    一.基于server端的session管理 在早期web应用中,通常使用服务端session来管理用户的会话.快速了解服务端session: 1) 服务端session是用户第一次访问应用时,服务器就 ...

  7. Uva821 Page Hopping (Floyd)

    题目大意: 最近的研究表明,互联网上任何一个网页在平均情况下最多只需要单击19次就能到达任 意一个其他网页.如果把网页看成一个有向图中的结点,则该图中任意两点间最短距离的平 均值为19. 输入一个n( ...

  8. 将jpg压缩成webp格式的图片

    cwebp名称 cwebp -压缩图像文件为的WebP文件概要 cwebp [选项] INPUT_FILE -o output_file.webp描述 cwebp压缩使用的WebP格式的图像.输入格式 ...

  9. 【转】PHP面试题总结

    PHP面试总结 PHP基础 1:变量的传值与引用. 2:变量的类型转换和判断类型方法. 3:php运算符优先级,一般是写出运算符的运算结果. 4:PHP中函数传参,闭包,判断输出的echo,print ...

  10. TensorFlow函数(十)tf.global_variables_initializer()

    tf.global_variables_initializer() 此函数是初始化模型的参数 with tf.Session() as sess: tf.global_variables_initia ...