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

API 介绍cf框架提供内置的异步库cf, 需要使用的时候我们必须先导入API: local cf = require "cf". 定时器与循环定时器cf库内置了一些定时器方法, 这些方法为开发者提供了对时间事件的控制能力. cf.timeout、cf.at、cf.sleep. cf.sleep方法是一个阻塞的定时器, 只有一个参数用来设置当前协程的休眠时间并且没有返回值. 此方法的行为(语义)取决于用户传入的参数: 当时间参数大于0的时候, 当前协程会暂停指定的时间且让出执行权. 当指定的时间超时后函数将会返回继续执行下面的代码.当时间参数等于0的时候, 当前协程会暂停并且让出执行权. 当其它协程执行完毕(让出)后立刻返回.当时间参数小于0或者非number类型的时候, 此方法将立刻返回.cf.timeout与cf.at不会阻塞当前协程执行流程. 目前虽然暴露给开发者使用, 但真正的使用场景都仅限于在需要长连接业务内. cf.timeout与cf.at都会返回一个timer对象, 开发者可以在任何时候使用timer对象的stop方法停止定时器. cf.timeout与cf.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.lualocal 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方法将当前定时器的运行信息打印出来(第几个创建的定时器与定时器时间). ...

June 24, 2019 · 2 min · jiezi

分布式系统关注点20阻塞与非阻塞有什么区别

如果第二次看到我的文章,欢迎「文末」扫码订阅我个人的公众号(跨界架构师)哟~ 每周五早8点 按时送达到公众号。当然了,也会时不时加个餐~前面一篇文章中,Z哥和你聊了「异步」的意义,以及如何运用它。错过这篇文章的可以先去看一下再来(分布式系统关注点——深入浅出「异步」)。 其实我知道有不少小伙伴容易将「异步」和「非阻塞」搞混。脑海里印象可能是这样的:异步=非阻塞,同步=阻塞? 其实并不是如此,Z哥我这次就想来帮你搞清楚这个问题。 同步与阻塞/非阻塞你平时编写的代码中,大部分的「同步」调用,本质上都是「阻塞」的。但是「同步」调用也可以做到「非阻塞」的效果。 还是拿我们上一篇中提到的排队买奶茶这个例子,看看为什么说是「同步」+「阻塞」。 文章里「同步」的例子说的是,你排队买奶茶,点完单继续“占着坑”,不让后面的人点单,等里面的店员做好奶茶,你拿走了后面的才能点单。这个其实就是「同步」+「阻塞」,「阻塞」体现在哪? 因为这个时候你一直“占着坑”,生怕后面的人先点单,导致店员给他先做。所以,这个时候你就死死的盯着里面,这个就是「阻塞」,因为你除了盯着其它啥都干不了。 怎么让「同步」也能不阻塞呢? 就是你虽然还是排着队“占着坑”,但是人没闲着,低头玩玩手机,时不时的问里面“我的奶茶做好了没?我的奶茶做好了没?”。这个就是「非阻塞」,因为你两次询问之间会间隔一段时间,可以在这个时候做其它的事情。本质上是通过将原本的一个「大同步」拆成多个「小同步」达到「非阻塞」的效果。 上图中,几次阻塞之间空白区域就可以用于做其它事,所以是「非阻塞」的。 异步与阻塞/非阻塞上一篇文章中的「异步」例子就是一个「非阻塞」的例子,我们来看看为什么。 奶茶店分了点单区和取餐区之后,做好的饮料就只能从取餐区拿,也意味着接待你进行点单的人并不是实际做奶茶的人。这个时候你会拿到一张取餐号,然后老老实实的去取餐区等着,而不是“占着xx不xx”。 如果你很着急要拿到奶茶,不断的问里面“我的奶茶做好了没?我的奶茶做好了没?”,那这个还是「同步」+「非阻塞」的模式。因为这个过程没有产生「回调」,是你在不断的主动发起“请求”。 但如果你不着急,就在边上开一局吃鸡,等着里面做好了叫号,到你号码了再去拿。这就是「异步」+「非阻塞」。因为这个事情是对方(里面的店员)触发完成的,这就是「回调」,是对你之前的“点单”请求进行的响应。一来一回完成一个完整的交互。 到这可能你会说,那异步不还是天然「非阻塞」的么?No、No、No。 阻塞不阻塞是你自己决定的,你可以阻塞啊。比如,你等的“回调”时候发现没带手机,玩不了吃鸡,那只能傻傻的在那等着,啥也干不了。如此,这个过程虽然还是「异步」的,但对你来说就是「阻塞」的。 工作中的同步/异步&阻塞/非阻塞「同步」+「阻塞」。这种最常见,平时写的大部分代码都是如此,就不多说了。 其实你仔细想一下就会发现,很多知名的框架,都是「同步」+「非阻塞」的,为什么呢?因为你可以继续像「同步」一样编写代码,但是可以享受到类似「异步」所能带来的更好的性能,何乐而不为? 比如大名鼎鼎的linux中的io复用模型poll/select/epoll,本质上都是「同步」+「非阻塞」的。还有知名网络通信框架Netty。 我们在设计对外的api的时候也可以使用这种模式,降低一些耗时接口调用所产生的影响。这个阮一峰老师已经写的非常清楚了,我就直接贴个链接:http://www.ruanyifeng.com/blo...。 之所以大家会有错觉,认为「异步」=「非阻塞」,其实也不是没有道理。为什么呢?因为我在脑海中搜寻来一番,的确没想到有什么知名的框架/设计是使用「异步」+「阻塞」来实现的。如果哪位小伙伴有补充,可以在评论区留言告诉大家。 「异步」+「非阻塞」就多了。任何你看到callback关键字的框架都是。 总结好了,我们一起总结一下。 这次呢,Z哥先通过同步/异步、阻塞/非阻塞之间形成的4种组合形式,聊了下它们到底是怎么回事。 然后和你聊了一下工作中哪里能看到它们的存在,以及在一些典型场景下适合用哪一种模式。 希望对你有所启发。 最后送你一个记住这4个概念的最好办法。 同步阻塞:你干吧,我看着你干同步非阻塞:你干吧,我每隔5分钟来看看异步阻塞:你干吧,好了告诉我,我等着异步非阻塞:你干吧,好了告诉我,我先去忙别的了如果还是记不住,那就记住同步/异步表示“过程”,阻塞/非阻塞表示在这个过程中的“状态”。至于这句话是怎么来的,回来看这篇文章就行。 相关文章: 分布式系统关注点——深入浅出「异步」分布式系统关注点——360°全方位解读「缓存」 作者:Zachary 出处:https://www.cnblogs.com/Zacha... 如果你喜欢这篇文章,可以点一下文末的「赞」。 这样可以给我一点反馈。: ) 谢谢你的举手之劳。 ▶关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描下方的二维码~。定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。 如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

May 24, 2019 · 1 min · jiezi

PHP socket初探 --- 一些零碎细节的拾漏补缺

原文:https://t.ti-node.com/thread/…前面可以说是弄了一系列的php socket和多进程的一大坨内容,知识浅显、代码粗暴、风格简陋,总的说来,还是差了一些细节。今天,就一些漏掉的细节补充一下。一些有志青年可能最近手刃了Workerman源码,对于里面那一大坨stream_select()、stream_socket_server()表示疑惑,这个玩意和socket_create、socket_set_nonblock()有啥区别?其实,php官方手册里也提到过一嘴,socket系函数就是基于BSD Socket那一套玩意搞的,几乎就是将那些东西简单包装了一下直接抄过来用的,抄到甚至连名字都和C语言操控socket的函数一模一样,所以说socket系函数是一种比较低级(Low-Level,这里的低级是指软件工程中分层中层次的高低)socket操控方式,可以最大程度给你操作socket的自由以及细腻度。在php中,socket系本身是作为php扩展而体现的,这个你可以通过php -m来查看有没有socket,这件事情意味着有些php环境可能没有安装这个扩展,这个时候你就无法使用socket系的函数了。但stream则不同了,这货是内建于php中的,除了能处理socket网络IO外,还能操控普通文件的打开写入读取等,stream系将这些输入输出统一抽象成了流,通过流来对待一切。有人可能会问二者性能上差距,但是本人没有测试过,这个我就不敢轻易妄言了,但是从正常逻辑上推演的话,应该不会有什么太大差距之类的。一定要分清楚监听socket和连接socket,我们服务器监听的是监听socket,然后accept一个客户端连接后的叫做连接socket。关于“异步非阻塞”,这五个字到底体现在哪儿了。swoole我就不说了,我源码也才阅读了一小部分,我就说Workerman吧,它在github上称:“Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications.”,看到其中有asynchronous(异步)的字样,打我脸的是我并没有看到有non-block(非阻塞)的字样,不过无妨,脸什么的不重要,重要的是我文章里那一坨又一坨的代码里哪里体现了非阻塞、哪里体现了异步。来吧,看代码吧。看代码前,你要理解异步和非阻塞的区别是什么,因为这二者在表现结果上看起来是有点儿相似的,如果你没搞明白,那么一定要通过这个来理解一下《PHP socket初探 — 关于IO的一些枯燥理论》。<?php// 创建一个监听socket,这个一个阻塞IO的socket$listen = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );socket_bind( $listen, ‘0.0.0.0’, 9999 );socket_listen( $listen );while( true ){ // socket_accept也是阻塞的,虽然有while,但是由于accpet是阻塞的,所以这段代码不会进入无限死循环中 $connect = socket_accept( $listen ); if( $connect ){ echo “有新的客户端”.PHP_EOL; } else { echo “客户端连接失败”.PHP_EOL; }}将上面代码保存了运行一下,然后用telnet可以连接上去。但是,这段代码中有两处是阻塞的,最主要就是监听socket是阻塞的。那么,非阻塞的监听socket会是什么感受?<?php// 创建一个监听socket,将其设置为非阻塞$listen = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );socket_bind( $listen, ‘0.0.0.0’, 9999 );socket_listen( $listen );// ⚠️⚠️⚠️⚠️⚠️⚠️ 这里设置非阻塞!socket_set_nonblock( $listen );while( true ){ $connect = socket_accept( $listen ); if( $connect ){ echo “有新的客户端”.PHP_EOL; } else { echo “客户端连接失败”.PHP_EOL; }}将代码保存了运行一下,告诉我:来来来,分析一波儿,为啥会出现这种现象。因为监听socket被设置成了非阻塞,我们知道非阻塞就是程序立马返回,然后再过段时间回来询问,用例子就是“等馒头过程中,看下微博,抬头问馒头好了吗?然后看下微信,抬头问馒头好了吗?然后看下v2ex,抬头问馒头好了吗?。。。 。。。”,这样你是不是就能理解了?因为并没有客户端连接进来,所以每当询问一次socket_accept后得到的反馈都是“没有连接”,所以就直接走到“客户端连接失败”的分支中去了,而且是不断的不停的。这个时候,你用htop或者top命令查看服务器CPU,不出意外应该是100%,这是非阻塞的极大缺点。紧接着是异步呢?异步体现在哪儿了?我们说异步,是你去阿梅那里买馒头,阿梅告诉你说“馒头还没好,你去干别的吧,好了我打电话通知你”,然后你就专心去打游戏去了,直到电话响了你去拿馒头。Workerman的异步更多是体现在对一个完整请求的处理流上,而不是正儿八经的异步的定义概念,如果你没听明白,那也可能正常,慢慢理解。最后,我补充一句:epoll是同步的,而不是异步。 ...

November 21, 2018 · 1 min · jiezi