博客
关于我
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/

    你可能感兴趣的文章
    Neo4j的安装与使用
    查看>>
    Neo4j(2):环境搭建
    查看>>
    Neo私链
    查看>>
    nessus快速安装使用指南(非常详细)零基础入门到精通,收藏这一篇就够了
    查看>>
    Nessus漏洞扫描教程之配置Nessus
    查看>>
    Nest.js 6.0.0 正式版发布,基于 TypeScript 的 Node.js 框架
    查看>>
    NetApp凭借领先的混合云数据与服务把握数字化转型机遇
    查看>>
    NetBeans IDE8.0需要JDK1.7及以上版本
    查看>>
    netcat的端口转发功能的实现
    查看>>
    netfilter应用场景
    查看>>
    netlink2.6.32内核实现源码
    查看>>
    Netpas:不一样的SD-WAN+ 保障网络通讯品质
    查看>>
    NetScaler的常用配置
    查看>>
    netsh advfirewall
    查看>>
    NETSH WINSOCK RESET这条命令的含义和作用?
    查看>>
    Netty WebSocket客户端
    查看>>
    netty 主要组件+黏包半包+rpc框架+源码透析
    查看>>
    Netty 异步任务调度与异步线程池
    查看>>
    Netty中集成Protobuf实现Java对象数据传递
    查看>>
    Netty事件注册机制深入解析
    查看>>