Lua Web快速开发指南(9) - 使用cf内置的异步库

栏目: Lua · 发布时间: 4年前

内容简介:cf框架提供内置的异步库cf库内置了一些定时器方法, 这些方法为开发者提供了对时间事件的控制能力.

API 介绍

cf框架提供内置的异步库 cf , 需要使用的时候我们必须先导入API: local cf = require "cf" .

定时器与循环定时器

cf库内置了一些定时器方法, 这些方法为开发者提供了对时间事件的控制能力. cf.timeoutcf.atcf.sleep .

cf.sleep 方法是一个 阻塞 的定时器, 只有一个参数用来设置当前协程的休眠时间并且没有返回值. 此方法的行为(语义)取决于用户传入的参数:

number

cf.timeoutcf.at 不会阻塞当前协程执行流程. 目前虽然暴露给开发者使用, 但真正的使用场景都仅限于在需要长连接业务内.

cf.timeoutcf.at 都会返回一个 timer 对象, 开发者可以在任何时候使用 timer 对象的 stop 方法停止定时器.

cf.timeoutcf.at 的参数如下:

  • 第一个参数是一个指定的时间, 其在现实中的时间比例为1:1.
  • 第二个参数是一个回调函数, 当时间事件触发后将会为用户执行用户定义的回调函数.

记住: cf.timeout 是一次性定时器, 回调函数被触发之后将会自动停止运行. 而 cf.at 如果不使用 stop 方法停止则会 一直重复执行 .

协程的使用、暂停、唤醒

cf库提供了 协程 的操作方法. 此 协程Lua 的原生协程有些许不同, cf基于原生协程的基础上由框架管理生命周期.

需要异步执行一个函数可以使用 cf.fork 创建一个由cf调度的协程, 此方法会返回一个协程对象. 这个协程对象可以在它让出的时候用来主动唤醒.

cf.fork 方法的第一个参数func为 function 类型, 从第二个参数开始的参数将会作为func的参数(一般情况下我们会利用upvalue而不会显示传递参数).

需要暂停一个cf创建的协程可以使用 cf.wait 方法. 此方法没有参数, 但如果调用此方法的协程不是由 cf 创建或不是 main 协程则会出错.

cf.wakeup 方法用于唤醒由 cf.wait 暂停的协程. cf.wait 方法的返回值由 cf.wakeup 的行为决定, 当唤醒的是不存在的协程或唤醒正在执行的协程将会出错.

cf.wakeup 方法的第一个参数是一个协程对象, 协程对象之后的所有参数将会返回给 cf.wait 进行接收.

需要获取当前协程对象的时候在这个协程执行流程之间使用 cf.self 方法获取, cf.self 的作用与内置库 coroutine.running 方法相同.

它返回一个协程对象与一个boolean值. 当协程对象为主( main )协程时则bolean为 true , 否则为 false .

更多详细的API介绍

更多使用介绍请参考 cf库 的文档.

开始实践

1. 随机生成三个定时器并且输出时间.

在本示例中! 我们首先修改随机数生成器种子, 随机从0~1中间取一个随机数作为定时器的时间. 然后启动一个循环开始生成3个定时器.

-- main.lua
local cf = require "cf"
math.randomseed(os.time()) -- 设置随机数种子
for index = 1, 3 do
  local time = math.random()
  cf.timeout(time, function()
    print("第"..index.."个定时器的时间为:"..time)
  end)
end

由于是随机生成的时间, 所以我们在函数内部使用print方法将当前定时器的运行信息打印出来(第几个创建的定时器与定时器时间).

现在让我们多运行几次来查看输出有什么不同:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
第2个定时器的时间为:0.0029842634685338
第1个定时器的时间为:0.12212080322206
第3个定时器的时间为:0.38623028574511
[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
第1个定时器的时间为:0.10055952938274
第3个定时器的时间为:0.30804532766342
第2个定时器的时间为:0.32007071143016
[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
第3个定时器的时间为:0.083867806941271
第2个定时器的时间为:0.52678858255967
第1个定时器的时间为:0.74910803744569

可以看到, 每次的输出内容因为随机数产生的数值不同而不同.

2. 定时器的启动与暂停

一个定时器的启动与停止必然是相对应的. 下面这个示例展示了如何启动与

-- main.lua
local cf = require "cf"
local timer = cf.timeout(1, function ()
  print("定时器触发")
end)

timer:stop()

在上述这段代码中, 我们启动了一个1秒的一次性定时器并且获取了一个 timer 的对象.

这个定时器会在 超时主动停止 后停止运行, 即使多次对同一个定时器对象调用 stop 方法也是无害的操作.

如果不出意外的情况下, 开发者应该会看到这样的输出内容:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
定时器触发
[candy@MacBookPro:~/Documents/core_framework] $

如果您注释掉 timer:stop() 这段代码, 将不会有任何内容输出.

3. 启动一个协程来实现异步任务.

cf的协程是任务执行的关键模块, 我们利用协程可以达到异步任务的使用效果.

下面这个示例展示了如何使用协程来执行异步任务:

-- main.lua
local cf = require "cf"

print("主协程开始运行..")

cf.fork(function ()
  print("cf的协程开始运行..")
end)

print("主协程开始休眠..")
cf.sleep(1)
print("主协程结束休眠..")

首先我们在主协程中创建了一个cf协程, 这个线程将在主协程睡眠(让出执行权)期间运行.

当主协程休眠结束后将继续运行. 所以, 它的输出应该是这样子的:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
主协程开始运行..
主协程开始休眠..
cf的协程开始运行..
cf的协程结束运行..
主协程结束休眠..

4. 协程之间的互相作用

我们来假设一个场景: 主协程创建一个协程执行循环计算任务, 当任务执行完毕后唤醒主协程并且将计算结果传递过来.

思路: 首先我们利用前面学到的API获取主协程对象, 然后创建一个新的协程来执行计算. 计算完成之后将结果返回.

-- main.lua
local cf = require "cf"

local co = cf.self()
print("主协程开始运行..")

cf.fork(function ()
  print("cf协程开始运行..")
  local result = 0
  for index = 1, 100 do
    result = result + index
  end
  print("cf协程运行完毕, 返回结果并且唤醒主协程..")
  return cf.wakeup(co, result)
end)

print("主协程休眠等待计算完成..")
local result = cf.wait()
print("主协程休眠结束获取到结果为:"..result)
print("主协程执行完毕..")

输出结果如下所示:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
主协程开始运行..
主协程休眠等待计算完成..
cf协程开始运行..
cf协程运行完毕, 返回结果并且唤醒主协程..
主协程休眠结束获取到结果为:5050
主协程执行完毕..

注意: 上述示例仅用于演示如何创建异步任务, 对CPU密集型运算毫无帮助. 真实使用场景一般是在IO密集型运算中使用.

5. 两种不同的循环定时器

首先我们根据上述的API创建 标准API 提供的循环定时器:

local cf  = require "cf"

local timer
local index = 1

timer = cf.at(1, function ()
  if index > 10 then
    print("定时器停止运行..")
    return timer:stop()
  end
  print("输出的数值为:", index)
  index = index + 1
end)

-- timer:stop()

输出如下:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
输出的数值为:    1
输出的数值为:    2
输出的数值为:    3
输出的数值为:    4
输出的数值为:    5
输出的数值为:    6
输出的数值为:    7
输出的数值为:    8
输出的数值为:    9
输出的数值为:    10
定时器停止运行..
[candy@MacBookPro:~/Documents/core_framework] $

上述代码在每次循环定时器超时的时候都会执行回调函数输出当前自增数值, 最后在达到一定次数后自动停止运行. 这种形式的写法也是作者所推荐的写法.

当然, 我们还有一种利用 cf.sleep特殊 的定时器写法:

cf.fork(function ()
  for index = 1, 10 do
    cf.sleep(1)
    print("输出的数值为:", index)
  end
  print("定时器停止运行..")
end)

它的输出如下:

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
输出的数值为:    1
输出的数值为:    2
输出的数值为:    3
输出的数值为:    4
输出的数值为:    5
输出的数值为:    6
输出的数值为:    7
输出的数值为:    8
输出的数值为:    9
输出的数值为:    10
定时器停止运行..
[candy@MacBookPro:~/Documents/core_framework] $

两种写法虽然行为上是一致, 但是两种不同的定时器的内部实现行为却是不一样.

第一种定时器无论在可读性与可控性上来看都做的非常好. 第二种虽然能模拟第一种的行为, 但是在内部需要多创建一个协程来实现唤醒并且无法被外部停止.

而且必须使用第二种定时器的场景一般是不存在的, 但是为了演示还是需要知会开发者尽量不要编写毫无好处的代码 :).

继续学习

下一章我们将学习如何使用MQ库来完成消息队列的任务监听.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python 3 the Hard Way

Learn Python 3 the Hard Way

Zed A. Shaw / Addison / 2017-7-7 / USD 30.74

You Will Learn Python 3! Zed Shaw has perfected the world’s best system for learning Python 3. Follow it and you will succeed—just like the millions of beginners Zed has taught to date! You bring t......一起来看看 《Learn Python 3 the Hard Way》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具