事件驱动模型

简介: 笔记

1. 概念


事件驱动:事件驱动是指在持续事务管理过程中,进行决策的一种策略,即跟随当前时间点上出现的事件,调动可用资源,执行相关任务,使不断出现的问题得以解决,防止事务堆积。事件驱动的核心自然是事件,从事件角度说,事件驱动程序的基本结构是由一个事件收集器、一个事件发送器和一个事件处理器组成。


2. 作用


事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。基于事件驱动的程序可以实时响应所关心的事件,可以实现模块之间的解耦、实现异步任务、跟踪状态变化。


3. 应用场景


Windows 本身是基于事件驱动模型的,目前大部分的UI编程也都是事件驱动模型。比如你现在的鼠标点击,按下鼠标就会产生一个onClick()事件,因为平台有注册相应的回调事件,每当点击就会触发该事件,然后交给对应的事件处理器进行处理。


事件驱动的大体逻辑如下:


存在一个消息队列,用于存储的各种事件

当触发了某个事件,就向队列中添加该事件

有循环不断从队列中取出事件,根据派发的不同事件,做相应的处理操作,调用不同的函数处理

事件一般都保存有自己的处理函数指针,每个事件都有独立的处理函数


4. 具体实现


个人简单理解:


事件驱动就是首先得有一个队列用于缓存事件,相当于一个信道。队列尾会一直添加触发的事件消息,之后有一个处理事件的循环,一直会从队列头取出事件,并执行事件自带的回调函数。


下面用事件驱动的方式【逆序一个文件】


1. 异步IO库

readline:读事件

writeline:写事件

stop:停止事件

loop:处理事件的循环

#!/usr/local/bin/lua
-- local queue = require "deque" -- 需要配置 path
dofile("../dataStructure/deque.lua") -- 路径不用管,就是导入自定义的deque
local queue = deque() 
local lib = {} 
function lib.readline(stream, callback) 
    local cmd = function()
        callback(stream:read())
    end
    queue.push_back(cmd)
end
function lib.writeline(stream, line, callback) 
    local cmd = function() 
        callback(stream:write(line))
    end
    queue.push_back(cmd)
end 
function lib.stop() 
    queue.push_back("stop")
end
function lib.loop()
    print("开始循环工作-------")
    while true do 
        local cmd = queue.pop_front() 
        if cmd == "stop" then print("[ cmd = 'stop' ]") break end 
        cmd()
    end
    print("结束循环工作-------")
end
return lib

2. 事件驱动

可以忽略一些打印信息的代码,方便之后的输出信息查看,理解运行的逻辑。


先调用getline进入文件准备开始读取第一行,然后执行loop开始去取第一条指令。这里getline是将自己作为回调函数注册进readline,指令一直运行相当于递归一直调用getline,并且从流中读入的数据作为getline的参数line存入表t中。


在读到文件尾,getline中会调用putline函数,同理递归的调用putline,逆序的输出了文件内容。


作为一种典型的事件驱动场景,由于主循环位于库async-lib.lua中,因此所有的循环都消失了,这些循环被以事件区分的递归调用所取代。


文件名:event_file.lua

#!/usr/local/bin/lua
local lib = require "async-lib"
local file_in = io.open("file_in.txt", "a+")
local input = io.input(file_in) 
local file_out = io.open("file_out.txt", "w+")
local output = io.output(file_out) 
local t = {} 
local i = 0
local label_putline = 0 
local label_getline = 0
local function putline() 
    if label_putline == 0 then  
        print("----------------------------------------")
        print("getline 已完成使命(读完文件所有内容)")
        print("----------------------------------------")
    end 
    print("现在调用: putline()")
    i = i - 1
    if i == 0 then 
        lib.stop() 
    else 
        lib.writeline(output, t[i] .. "\n", putline)
        print(string.format("第[ %d ]写入", label_putline + 1))
        label_putline = label_putline + 1
    end
end
local function getline(line) 
    if label_getline == 0 then 
        print("----------------------------------------")
        print("getline 开始读文件内容")
        print("----------------------------------------")
    end 
    print("现在调用:getline(line)")
    if line then 
        t[#t + 1] = line 
        lib.readline(input, getline) 
        print(string.format("第[ %d ]读入", label_getline + 1))
        label_getline = label_getline + 1
    else 
        i = #t + 1 
        putline() 
    end 
end
lib.readline(input, getline) -- 读取第一行开始
lib.loop() -- 运行主循环
io.close(file_in)
io.close(file_out)

3. 协程重写

协程可以让我们使用事件循环来简化循环的代码,其核心思想是使用协程运行主要代码,即在每次调用库时将回调函数设置为唤醒协程的函数,然后让出执行权。

下面例子是使用异步库运行同步代码

文件名:coroutine_file.lua

#!/usr/local/bin/lua
local lib = require "async-lib"
function run(code) 
    local co = coroutine.wrap(function()
        code() 
        lib.stop() -- 所有code逻辑运行完,停止
    end)
    co() -- 开始运行,然后进到code()逻辑
    -- 阻塞在第一次yield,然后执行lib.loop
    lib.loop() -- 开始事件循环 
end
function putline(stream, line) 
    local co = coroutine.running() 
    local callback = (function() coroutine.resume(co) end)
    lib.writeline(stream, line, callback)
    coroutine.yield()
end
function getline(stream, line) 
    local co = coroutine.running() 
    local callback = (function(l) coroutine.resume(co, l) end)
    lib.readline(stream, callback)
    local line = coroutine.yield()
    return line
end
run(function() 
    local t = {} 
    local file_in = io.open("file_in.txt", "a+")
    local file_out = io.open("file_out.txt", "w+")
    local input = io.input(file_in) 
    local output = io.output(file_out) 
    while true do 
        local line = getline(input) 
        if not line then break end 
        t[#t + 1] = line 
    end 
    for i = #t, 1, -1 do 
        putline(output, t[i] .. "\n")
    end 
    io.close(file_in)
    io.close(file_out)
end)

文件:file_in.txt

start
1 line 
2 line 
3 line 
4 line 
5 line 
end


文件:file_out.txt

end
5 line 
4 line 
3 line 
2 line 
1 line 
start


输出

开始循环工作-------
----------------------------------------
getline 开始读文件内容
----------------------------------------
现在调用:getline(line)
第[ 1 ]读入
现在调用:getline(line)
第[ 2 ]读入
现在调用:getline(line)
第[ 3 ]读入
现在调用:getline(line)
第[ 4 ]读入
现在调用:getline(line)
第[ 5 ]读入
现在调用:getline(line)
第[ 6 ]读入
现在调用:getline(line)
第[ 7 ]读入
现在调用:getline(line)
----------------------------------------
getline 已完成使命(读完文件所有内容)
----------------------------------------
现在调用: putline()
第[ 1 ]写入
现在调用: putline()
第[ 2 ]写入
现在调用: putline()
第[ 3 ]写入
现在调用: putline()
第[ 4 ]写入
现在调用: putline()
第[ 5 ]写入
现在调用: putline()
第[ 6 ]写入
现在调用: putline()
第[ 7 ]写入
现在调用: putline()
[ cmd = 'stop' ]
结束循环工作-------


相关文章
|
8月前
|
C语言
实现一个简单的事件驱动处理框架
实现一个简单的事件驱动处理框架
75 0
|
12天前
|
监控 数据处理
事件驱动架构的优势
事件驱动架构的优势
|
14天前
|
监控 Serverless API
阿里云函数计算的工作原理与事件驱动模型密切相关
【4月更文挑战第17天】阿里云函数计算的工作原理与事件驱动模型密切相关
68 4
|
6月前
|
存储 索引
2.2 事件驱动的reactor网络设计模型
2.2 事件驱动的reactor网络设计模型
20 0
|
7月前
|
消息中间件 存储 API
EDA - 初探事件驱动
EDA - 初探事件驱动
43 0
|
8月前
|
负载均衡 应用服务中间件 nginx
eda事件驱动架构
eda事件驱动架构
|
12月前
|
消息中间件 存储 监控
【事件驱动架构】专家组:事件驱动的大规模架构
【事件驱动架构】专家组:事件驱动的大规模架构
|
12月前
|
存储 机器学习/深度学习 消息中间件
[事件驱动架构 ]事件驱动2.0 事件,存储和处理统一到一个平台
[事件驱动架构 ]事件驱动2.0 事件,存储和处理统一到一个平台
|
消息中间件 安全 Java
深入事件驱动模式
深入事件驱动模式
141 0
深入事件驱动模式
事件驱动式编程
事件驱动式编程
119 1