主页 > 其他  > 

Lua|每日一练(4)

Lua|每日一练(4)

💢欢迎来到张胤尘的技术站 💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥

文章目录 Lua | 每日一练 (4)题目参考答案线程和协程调度方式上下文切换资源占用实现机制使用场景 `lua` 中的协程协程的生命周期主要函数创建协程启动或恢复协程检查当前是否在主协程中运行暂停协程检测协程是否可暂停获取协程状态包装函数关闭协程 具体使用

Lua | 每日一练 (4) 题目

协程和线程有何区别?简述 lua 中的协程。

参考答案 线程和协程

协程和线程虽然在某些方面有相似之处,但它们在设计目标、实现原理和使用方式上有很大的区别。下面从调用方式、上下文切换、资源使用、实现机制、使用场景这几个方面进行阐述。

调度方式 线程:线程的执行由操作系统内核控制,操作系统会根据调度算法(如时间片轮转、优先级调度等)自动切换线程的执行。另外,线程的切换时间点不可预测,程序无法直接控制线程的暂停和恢复。协程:协程的执行由程序显式控制,需要开发者通过 coroutine.yield 和 coroutine.resume 显式地暂停和恢复协程。协程的切换完全由程序逻辑决定,切换点是明确的。 上下文切换 线程:线程切换涉及操作系统内核的上下文切换,需要保存和恢复线程的寄存器状态、栈信息等,开销较大。协程:协程的上下文切换在用户态完成,不需要操作系统内核介入,开销非常小。 资源占用 线程:每个线程都有自己的栈空间,通常默认分配 8 MB,资源占用较大。如果线程数量过多会导致系统资源耗尽。 $ ulimit -s 8192 协程:协程的栈空间是动态分配的,通常占用较少的内存。另外,协程的数量可以非常大,适合处理大规模的并发任务。 实现机制 线程:线程是操作系统提供的并发机制,由操作系统内核管理。线程的创建和销毁需要系统调用,涉及内核态和用户态的切换。协程:协程是语言层面的机制,由 lua 解释器实现。协程的创建和切换完全在用户态完成,不涉及操作系统内核。 使用场景 线程:适合处理真正的并发任务,例如多核 CPU 上的并行计算,处理 I/O 密集型任务。协程:适合处理单核 CPU 上的并发任务,尤其是需要频繁切换的场景;适合实现非阻塞 I/O 操作,例如网络编程中的异步请求处理。 lua 中的协程

在 lua 中,协程是实现异步编程的核心工具之一。由于 lua 本身没有内置的多线程支持,而协程提供了一种轻量级的并发机制,可以用来模拟异步操作,从而实现非阻塞的程序设计。

协程的生命周期

lua 协程的生命周期包括以下几个阶段:

创建:使用 coroutine.create 创建一个协程。此时协程处于挂起状态,尚未开始执行。运行:使用 coroutine.resume 启动或恢复协程的执行。暂停:在协程执行过程中,可以通过 coroutine.yield 暂停协程的执行,将控制权交回主程序。结束:当协程运行完成或因错误终止时,协程进入结束状态。

协程的状态之间切换,如下图所示:

主要函数

下面介绍 lua 中关于协程的主要函数。

创建协程 local co = coroutine.create(f) f:协程函数,表示协程的主体逻辑。返回一个协程对象 co,类型为 thread。协程对象可以用于后续的 coroutine.resume 和 coroutine.yield 等操作。

例如:

-- func 是协程函数,主体逻辑 local function func() print("Coroutine is running") end -- 创建协程 local co = coroutine.create(func) print(co) -- thread: 0x60f0c8666df8 启动或恢复协程 ok, ... = coroutine.resume(co, ...) co:要启动或者恢复的协程对象。...:可选参数,这些参数会传递给协程中的 coroutine.yield 或协程的入口函数。ok:布尔值,表示协程是否成功恢复。如果协程因错误终止,返回 false。...:协程中 coroutine.yield 的返回值。如果协程运行完成,返回值为 nil。

说明:

如果协程处于 suspended 状态,coroutine.resume 会启动或恢复协程的执行。如果协程已经处于 running 状态,调用 coroutine.resume 会抛出错误。如果协程已经处于 dead 状态,调用 coroutine.resume 也会抛出错误。

例如:

local function func(x, y) print("Coroutine started with:", x, y) -- Coroutine started with: 10 20 end local co = coroutine.create(func) local ok, result = coroutine.resume(co, 10, 20) print(ok, result) -- true nil 检查当前是否在主协程中运行 current_co, is_main = coroutine.running() current_co:当前运行的协程对象。is_main:布尔值,表示当前是否在主协程中运行,如果是主协程返回 true,否则返回 false。

说明:

用于检查当前是否在主协程中运行,以及当前协程是否是主线程。

例如:

local function printCurrentCoroutine() local current_co, is_main = coroutine.running() print(current_co, is_main) end printCurrentCoroutine() -- thread: 0x61617e0492a8 true local co = coroutine.create(function() print("Printing from the coroutine") -- Printing from the coroutine printCurrentCoroutine() -- thread: 0x61617e04fec8 false end) coroutine.resume(co) -- 启动协程 暂停协程 ... = coroutine.yield(...) ...:可选参数,这些参数会传递给调用 coroutine.resume 的代码。返回值是 coroutine.resume 调用时传递的参数。

说明:

coroutine.yield 用于暂停当前协程的执行,并将控制权返回给调用 coroutine.resume 的代码。协程暂停后,可以通过再次调用 coroutine.resume 恢复执行。

例如:

local function func() print("Coroutine running") -- Coroutine running local value = coroutine.yield("Yielded value") print("Coroutine resumed with:", value) -- Coroutine resumed with: Hello end local co = coroutine.create(func) local ok, result = coroutine.resume(co) print(ok, result) -- true Yielded value local ok, result = coroutine.resume(co, "Hello") print(ok, result) -- true nil 检测协程是否可暂停 is_yieldable = coroutine.isyieldable([co]) co:可选参数,表示要检查的协程对象。默认为当前运行的协程。is_yieldable:布尔值,表示协程是否可以暂停。

说明:

如果协程不是主协程且不在非可暂停的 C 函数中,则返回 true。主协程调用时返回 false。协程处于 suspended、dead 状态时 coroutine.isyieldable 仍然返回 true,因为协程对象本身仍然是有效的,并且在 lua 的语义中,dead 状态的协程仍然可以被认为是可以暂停的(尽管它已经无法再被恢复)。

例如:

local co = coroutine.create(function() print(coroutine.isyieldable()) -- true coroutine.yield() end) coroutine.resume(co) -- 启动协程 print(coroutine.isyieldable(co)) -- true print(coroutine.status(co)) -- suspended coroutine.resume(co) print(coroutine.status(co)) -- dead print(coroutine.isyieldable(co)) -- true print(coroutine.isyieldable()) -- false 获取协程状态 status = coroutine.status(co) co:要检查状态的协程对象。返回一个字符串,表示协程的当前状态: `running:协程正在运行。suspended:协程处于暂停状态。dead:协程已经运行完成或因错误终止。normal:协程尚未启动(初始状态)。

例如:

local function func(co) local status = coroutine.status(co) print(status) -- running coroutine.yield("hello, world!") end local co = coroutine.create(func) local status = coroutine.status(co) print(status) -- suspended local ok, result = coroutine.resume(co, co) print(ok, result) -- true hello, world! local ok, result = coroutine.resume(co, co) print(ok, result) -- true nil local status = coroutine.status(co) print(status) -- dead 包装函数 f = coroutine.wrap(f) f:协程函数,表示协程的主体逻辑。返回一个包装函数 f。调用这个包装函数时,会自动启动或恢复协程的执行。

说明:

coroutine.wrap 是 coroutine.create 和 coroutine.resume 的简化版本。包装函数的返回值是协程中 coroutine.yield 的参数。如果协程运行完成,包装函数返回 nil;如果协程因错误终止,会抛出错误。

例如:

local wrapped = coroutine.wrap(function() print("Coroutine running") local value = coroutine.yield("Yielded value") print("Coroutine resumed with:", value) end) local result = wrapped() print(result) -- Yielded value wrapped("Hello") -- Coroutine resumed with: Hello 关闭协程 ok, err = coroutine.close(co)

co:要关闭的协程对象,协程的状态必须是 suspended 或 dead 状态。

ok:布尔值,表示操作是否成功。

err:如果操作失败,返回错误信息。

说明:

关闭协程 co,将其状态设置为 dead,并关闭协程中所有待关闭的变量。如果协程已经是 dead 状态,调用 coroutine.close 会返回 true。

例如:

local co = coroutine.create(function() coroutine.yield() -- 暂停协程 end) coroutine.resume(co) -- 启动协程 print(coroutine.status(co)) -- suspended local ok, err = coroutine.close(co) -- 关闭协程 print(ok, err) -- true nil print(coroutine.status(co)) -- dead 具体使用

使用协程实现经典的生产者-消费者模型。协程的暂停和恢复特性非常适合这种场景,因为生产者和消费者可以分别在协程中运行,通过共享队列进行通信。

一个简单的生产者-消费者模型实现,如下所示:

-- 队列实现 local Queue = {} function Queue:new() local obj = {} setmetatable(obj, self) self.__index = self obj.list = {} return obj end function Queue:put(item) table.insert(self.list, item) end function Queue:get() if #self.list <= 0 then return nil end local item = self.list[1] table.remove(self.list, 1) return item end function Queue:is_empty() return #self.list == 0 end -- 生产者函数 local function producer(queue, count) for i = 1, count do print("Produced:", i) queue:put(i) coroutine.yield() end end -- 消费者函数 local function consumer(queue, count) for i = 1, count do while queue:is_empty() do print("Waiting for item...") coroutine.yield() end local item = queue:get() print("Consumed:", item) end end local queue = Queue:new() local count = 100 -- 生产/消费数量 -- 创建生产者和消费者协程 local co_producer = coroutine.create(function() producer(queue, count) end) local co_consumer = coroutine.create(function() consumer(queue, count) end) -- 同时运行生产者和消费者协程 while coroutine.status(co_producer) ~= "dead" or coroutine.status(co_consumer) ~= "dead" do if coroutine.status(co_producer) ~= "dead" then coroutine.resume(co_producer) end if coroutine.status(co_consumer) ~= "dead" then coroutine.resume(co_consumer) end end

🌺🌺🌺撒花!

如果本文对你有帮助,就点关注或者留个👍 如果您有任何技术问题或者需要更多其他的内容,请随时向我提问。

标签:

Lua|每日一练(4)由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Lua|每日一练(4)