文档章节

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

水果糖的小铺子
 水果糖的小铺子
发布于 06/23 23:05
字数 2596
阅读 15
收藏 0

API 介绍

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

定时器与循环定时器

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

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

  • 当时间参数大于0的时候, 当前协程会暂停指定的时间且让出执行权. 当指定的时间超时后函数将会返回继续执行下面的代码.

  • 当时间参数等于0的时候, 当前协程会暂停并且让出执行权. 当其它协程执行完毕(让出)后立刻返回.

  • 当时间参数小于0或者非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库来完成消息队列的任务监听.

© 著作权归作者所有

水果糖的小铺子
粉丝 23
博文 153
码字总数 73315
作品 1
广州
程序员
私信 提问
Lua Web快速开发指南(1) - 初识cf框架

cf是什么? cf全称为: CoreFramework. 一个基于Reactor事件驱动与协程的lua高性能网络框架, 目前主要面向HTTP Application开发. cf内部主要实现了包括HTTP与HTTP Over Websoket协议的Server,...

水果糖的小铺子
06/14
131
0
Lua Web快速开发指南(2) - cf的运行机制简介与基于httpd库的开发环境搭建

从本章开始假设大家都熟悉lua语法. 运行流程 在上一章节学会了如何安装cf后, 本章节就会介绍cf到运行机制与httpd的server搭建! cf是一个非常典型的基于协程的事件驱动开发框架在封装成API后,...

水果糖的小铺子
06/14
27
0
core_framework 0.4 发布,提供 windows 平台支持

更新日志 修复的字段错误的问题. 修复在平台的莫名其妙段错误. 修复了默认不使用的问题. 优化函数的实现方法, 使用更加简单的函数实现. 优化了对各种后端选择的优先级判断. 优化一大部分 C ...

水果糖的小铺子
07/15
1K
0
core_framework —— 基于libev的轻量级lua网络开发框架

大道至简, 返璞归真. 前言 在发表这篇博文的前夕, 还有一些小伙伴在提问一些以下相关的问题: 性能怎么样? 是否容易上手? 开发目标在哪? 如何反馈问题? 对比行业内的lua开源项目有何优势? 等...

水果糖
03/27
75
0
精巧的 Lua web 开发框架 - cf

cf是什么? 1. 重度Lua使用者喜欢的web开发框架; 2. 极简主义hacker自定义web工具; 3. 比tiny更tiny的高效web开发库; 如果你也喜欢lua 如果你和我一样用过各种语言的各种开发框架, 你就慢慢变...

匿名
01/25
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

java数据类型

基本类型: 整型:Byte,short,int,long 浮点型:float,double 字符型:char 布尔型:boolean 引用类型: 类类型: 接口类型: 数组类型: Byte 1字节 八位 -128 -------- 127 short 2字节...

audience_1
30分钟前
4
0
太全了|万字详解Docker架构原理、功能及使用

一、简介 1、了解Docker的前生LXC LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpa...

Java技术剑
31分钟前
7
0
Wifiphisher —— 非常非常非常流氓的 WIFI 网络钓鱼框架

编者注:这是一个非常流氓的 WIFI 网络钓鱼工具,甚至可能是非法的工具(取决于你的使用场景)。在没有事先获得许可的情况下使用 Wifiphisher 攻击基础网络设施将被视为非法活动。使用时请遵...

红薯
今天
44
1
MongoDB 4 on CentOS 7安装指南

本教程为CentOS x86_64 7.x操作系统下,MongoDB Community x86_64 4.2(GA)安装指南。 安装方式一:yum repo在线安装 [此方式较为简单,官方推荐] Step1:新建MongDB社区版Yum镜像源。 # vim ...

王焱君
今天
7
0
go-micro 入门教程1.搭建 go-micro环境

微服务的本质是让专业的人做专业的事情,做出更好的东西。 golang具备高并发,静态编译等特性,在性能、安全等方面具备非常大的优势。go-micro是基于golang的微服务编程框架,go-micro操作简单...

非正式解决方案
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部