博客
关于我
Lua 中的协程分享
阅读量:486 次
发布时间:2019-03-07

本文共 2458 字,大约阅读时间需要 8 分钟。

Lua 协程详解

Lua协程是一个非常有趣的概念,它与传统的多线程有着本质的不同。借助协程,开发者可以充分发挥现代多核处理器的性能,同时保持程序的简单性。以下将从协程的基本原理、使用方法以及实际应用场景展开详细讨论。


协程的基本概念

协程是一种轻量级的用户空间线程,它与传统的操作系统线程有着显著的不同。传统的多线程执行是由操作系统统一调度的,采用抢占式的 overrun(抢占)。而协程则遵循协作式的执行模型,每个协程都自主决定何时暂停并将执行权交给下一个协程。

这意味着在多核处理器上,传统多线程可以充分利用多个核心,而协程却不能通过多核的优势,它只能在单个核心上执行。这种特性使得协程更适合处理I/O密集型的任务。


协程的状态管理

一个协程的生命周期通常包含三个状态:

  • 挂起态(suspended):默认状态。
  • 运行态(running):协程正在执行。
  • 停止态(dead):协程已终止。
  • 开发者可以通过 coroutine.status 方法检查当前协程的状态。

    通过 coroutine.create 函数可以创建一个新的协程,但需注意,该函数仅创建协程,并不会自动启动执行。要启动协程,需要调用 coroutine.resume 方法。


    协程的创建与启动

    创建一个简单的协程如下:

    hxc = coroutine.create(function ()    print("hi coroutine")end)

    调用 coroutine.resume(hxc) 即可启动协程执行。此时,hxc 将从主函数开始执行。运行到遇到 yield 调用或终止时,协程将进入挂起态。


    协程的暂停与恢复

    协程的独特之处在于其支持协作式并发。通过 yield 方法,可以将当前协程暂停,并将控制权交给其他协程或主线程。

    一个简单的用法示例如下:

    hxc = coroutine.create(function ()    for i = 1, 10 do        print("iter", i)        coroutine.yield()    endend)-- 当前线程执行coroutine.resume(hxc) -- 输出 iter 1-- 恢复协程,继续执行coroutine.resume(hxc) -- 输出 iter 2

    在遇到 yield 调用时,hxc 协程会暂停,当前线程继续执行其他任务。再次调用 coroutine.resume(hxc) 时,hxc 将从 yield 的位置继续执行,直到再次遇到 yield 或程序终止。


    协程间数据传递的两种方式

    协程通过 coroutine.resume 方法与 yield 调用进行数据交换。


    方法一:通过 resume 传递参数

    hxc = coroutine.create(function (a, b)    print("hxc", a, b, c)end)coroutine.resume(hxc, 1, 2) -- 输出:hxc 1 2

    在这种模式中,a 和 b 被传递给(coords)主函数,从而激活被挂起的协程。


    方法二:通过 yield 传递数据

    hxc = coroutine.create(function (a, b)    coroutine.yield(a + b, a - b)end)coroutine.resume(hxc, 20, 10) -- 输出:true 30 10-- 可以看到,`resume` 方法传入的参数会被传递给 `yield` 调用

    方法三:单参数的 resume 调用

    hxc = coroutine.create(function ()    coroutine.yield()end)coroutine.resume(hxc, 4, 5) -- 输出:true 4,5

    在这种情况下,4 和 5 会被传递给 yield 调用,从而激活协程。


    协程的实际应用

    协程主要用于处理I/O密集型任务,其中最常见的场景是异步操作处理。例如:

    异步文件操作

    在处理大量文件时,传统方法会导致主线程被长时间占用,影响用户体验。协程可以通过异步操作模拟同步代码:

    local file = io.stdinlocal line = ""while true do    line = file:read()    if not line then break end    coroutine.yield(line)    file: seek(0)end

    网络通信

    协程特别适合处理多次 socket 连接或请求。例如:

    distint_phones = {    "12345", "67890", "10101"}local socket = socket.tcp()socket:close() -- 停止当前连接while true do    socket = socket:bind("127.0.0.1", 8080)    socket:listen()    client, err = socket accept()    if client then        data, err = client recv()        if err then break end        coroutine.yield(data)    endend

    协程与传统多线程的对比

    协程的主要优势在于执行控制权的自主性,但其在多核环境上却不如多线程高效。以下是两者的主要区别:

    特性 传统多线程 协程
    调度方式 系统统一调度 由协程决定
    并发控制 抢占式执行 协作式执行
    性能表现 可以利用多核 不利用多核
    上下文切换 系统层面 用户层面

    因此,在需要充分发挥多核优势的情况下,传统多线程更为合适。而协程的应用场景主要集中在I/O-bound任务和需要冗余控制流程的场合。

    转载地址:http://cmedz.baihongyu.com/

    你可能感兴趣的文章
    Node.js 之 log4js 完全讲解
    查看>>
    Node.js 函数是什么样的?
    查看>>
    Node.js 函数计算如何突破启动瓶颈,优化启动速度
    查看>>
    Node.js 切近实战(七) 之Excel在线(文件&文件组)
    查看>>
    node.js 初体验
    查看>>
    Node.js 历史
    查看>>
    Node.js 在个推的微服务实践:基于容器的一站式命令行工具链
    查看>>
    Node.js 实现类似于.php,.jsp的服务器页面技术,自动路由
    查看>>
    Node.js 异步模式浅析
    查看>>
    node.js 怎么新建一个站点端口
    查看>>
    Node.js 文件系统的各种用法和常见场景
    查看>>
    Node.js 模块系统的原理、使用方式和一些常见的应用场景
    查看>>
    Node.js 的事件循环(Event Loop)详解
    查看>>
    node.js 简易聊天室
    查看>>
    Node.js 线程你理解的可能是错的
    查看>>
    Node.js 调用微信公众号 API 添加自定义菜单报错的解决方法
    查看>>
    node.js 配置首页打开页面
    查看>>
    node.js+react写的一个登录注册 demo测试
    查看>>
    Node.js中环境变量process.env详解
    查看>>
    Node.js之async_hooks
    查看>>