当前位置: 首页 > news >正文

Lua | 每日一练 (4)

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

文章目录

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

Lua | 每日一练 (4)

题目

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

参考答案

线程和协程

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

调度方式
  • 线程:线程的执行由操作系统内核控制,操作系统会根据调度算法(如时间片轮转、优先级调度等)自动切换线程的执行。另外,线程的切换时间点不可预测,程序无法直接控制线程的暂停和恢复。
  • 协程:协程的执行由程序显式控制,需要开发者通过 coroutine.yieldcoroutine.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.resumecoroutine.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
endlocal 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)
endprintCurrentCoroutine() -- thread: 0x61617e0492a8	truelocal co = coroutine.create(function()print("Printing from the coroutine") -- Printing from the coroutineprintCurrentCoroutine()              -- 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 runninglocal value = coroutine.yield("Yielded value")print("Coroutine resumed with:", value) -- Coroutine resumed with:	Hello
endlocal co = coroutine.create(func)
local ok, result = coroutine.resume(co)
print(ok, result) -- true	Yielded valuelocal ok, result = coroutine.resume(co, "Hello")
print(ok, result) -- true	nil
检测协程是否可暂停
is_yieldable = coroutine.isyieldable([co])
  • co:可选参数,表示要检查的协程对象。默认为当前运行的协程。
  • is_yieldable:布尔值,表示协程是否可以暂停。

说明:

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

例如:

local co = coroutine.create(function()print(coroutine.isyieldable()) -- truecoroutine.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) -- runningcoroutine.yield("hello, world!")
endlocal co = coroutine.create(func)
local status = coroutine.status(co)
print(status) -- suspendedlocal ok, result = coroutine.resume(co, co)
print(ok, result) -- true	hello, world!local ok, result = coroutine.resume(co, co)
print(ok, result) -- true	nillocal status = coroutine.status(co)
print(status) -- dead
包装函数
f = coroutine.wrap(f)
  • f:协程函数,表示协程的主体逻辑。
  • 返回一个包装函数 f。调用这个包装函数时,会自动启动或恢复协程的执行。

说明:

  • coroutine.wrapcoroutine.createcoroutine.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 valuewrapped("Hello") -- Coroutine resumed with:	Hello
关闭协程
ok, err = coroutine.close(co)
  • co:要关闭的协程对象,协程的状态必须是 suspendeddead 状态。

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

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

说明:

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

例如:

local co = coroutine.create(function()coroutine.yield() -- 暂停协程
end)coroutine.resume(co)                -- 启动协程
print(coroutine.status(co))         -- suspendedlocal 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 = selfobj.list = {}return obj
endfunction Queue:put(item)table.insert(self.list, item)
endfunction Queue:get()if #self.list <= 0 thenreturn nilendlocal item = self.list[1]table.remove(self.list, 1)return item
endfunction Queue:is_empty()return #self.list == 0
end-- 生产者函数
local function producer(queue, count)for i = 1, count doprint("Produced:", i)queue:put(i)coroutine.yield()end
end-- 消费者函数
local function consumer(queue, count)for i = 1, count dowhile queue:is_empty() doprint("Waiting for item...")coroutine.yield()endlocal item = queue:get()print("Consumed:", item)end
endlocal 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" doif coroutine.status(co_producer) ~= "dead" thencoroutine.resume(co_producer)endif coroutine.status(co_consumer) ~= "dead" thencoroutine.resume(co_consumer)end
end

🌺🌺🌺撒花!

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

在这里插入图片描述

相关文章:

Lua | 每日一练 (4)

&#x1f4a2;欢迎来到张胤尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 Lua | 每日一练 (4)题目参考答案线程和协程调度方式上…...

每日一题——接雨水

接雨水问题详解 问题描述 给定一个非负整数数组 height&#xff0c;表示每个宽度为 1 的柱子的高度图。计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#…...

java常见面试01

为什么重写 equals 还要重写 hashcode &#x1f308; 核心原因&#xff1a; 当两个对象通过equals()判断为相等时&#xff0c;它们的hashCode()必须返回相同的整数值&#xff01;这是Java世界的交通规则哦~&#xff08;交警曼波敬礼.jpg&#xff09; &#x1f9e9; 具体场景…...

算法-二叉树篇27-把二叉搜索树转换为累加树

把二叉搜索树转换为累加树 力扣题目链接 题目描述 给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提…...

C语言:51单片机 基础知识

一、单片机概述 单片机的组成及其特点 单片机是指在一块芯片上集成了CPU、ROM、RAM、定时器/计数器和多种I/O接口电路等&#xff0c;具有一定规模的微型计算机。 特点&#xff1a; 1、单片机的存储器以ROM、RAM严格分工。 2、采用面向控制的指令系统。 3、单片机的I/O口引脚通…...

olmOCR:使用VLM解析PDF

在PDF解析中&#xff0c;目前主流的开源工具包括Minuer、GOT OCR等。主要都是通过飞桨等OCR套件组装的一套pipeline&#xff0c;或者直接通过VLM解析图像。 #一、 olmOCR是使用VLM进行的端到端的PDF文档解析 二、document-anchoring 与上述的不同在于&#xff0c;olmOCR使用…...

数据结构(初阶)(七)----树和二叉树(堆,堆排序)

八&#xff0c;树与二叉树 树 概念与结构 树是⼀种⾮线性的数据结构&#xff0c;它是由 n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;⽽叶朝下的。 • 有⼀…...

图像分类项目1:基于卷积神经网络的动物图像分类

一、选题背景及动机 在现代社会中&#xff0c;图像分类是计算机视觉领域的一个重要任务。动物图像分类具有广泛的应用&#xff0c;例如生态学研究、动物保护、农业监测等。通过对动物图像进行自动分类&#xff0c;可以帮助人们更好地了解动物种类、数量和分布情况&#xff0c;…...

Kali Linux 2024.4版本全局代理(wide Proxy)配置,适用于浏览器、命令行

1. 网络拓扑介绍&#xff08;不使用虚拟机直接跳到2&#xff09; 虚拟机&#xff1a;VMware 17 Pro&#xff0c;为本机开启桥接模式。 我的究极套娃网络&#xff1a;手机V2rayNG代理端口为10808&#xff0c;开热点 -> 电脑连接wifi -> 虚拟机中运行kali 2. kali 配置…...

[Windows] 批量为视频或者音频生成字幕 video subtitle master 1.5.2

Video Subtitle Master 1.5.2 介绍 Video Subtitle Master 1.5.2 是一款功能强大的客户端工具&#xff0c;能够批量为视频或音频生成字幕&#xff0c;还支持批量将字幕翻译成其他语言。该工具具有跨平台性&#xff0c;无论是 mac 系统还是 windows 系统都能使用。 参考原文&a…...

不要升级,Flutter Debug 在 iOS 18.4 beta 无法运行,提示 mprotect failed: Permission denied

近期如果有开发者的 iOS 真机升级到 18.4 beta&#xff0c;大概率会发现在 debug 运行时会有 Permission denied 的相关错误提示&#xff0c;其实从 log 可以很直观看出来&#xff0c;就是 Dart VM 在初始化时&#xff0c;对内核文件「解释运行&#xff08;JIT&#xff09;」时…...

介绍 torch-mlir 从 pytorch 生态到 mlir 生态

一、引言 The Torch-MLIR project provides core infrastructure for bridging the PyTorch ecosystem and the MLIR ecosystem. For example, Torch-MLIR enables PyTorch models to be lowered to a few different MLIR dialects. Torch-MLIR does not attempt to provide a…...

upload

&#xff08;上传一句话木马&#xff0c;用蚁剑链接验证是否成功/传有回显的&#xff1a;<?php phpinfo();?>&#xff09; 学看代码 #function checkfile(){}&#xff1a;定义了一个名叫checkfile的函数 #var file方法.(获取名为‘upload_file’的元素)[获取哪些&…...

InterHand26M(handposeX-json 格式)数据集-release >> DataBall

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” 贵在坚持&#xff01; ---------------------------------------…...

[Java基础] JVM常量池介绍(BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗)

文章目录 1. JVM内存模型2. 常量池中有什么类型&#xff1f;3. 常量池中真正存储的内容是什么4. 判断一个字符串(引用)是否在常量池中5. BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗&#xff1f;6. 获取堆内存使用情况、非堆内存使用情况 1. JVM内…...

`maturin`是什么:matu rus in python

maturin是什么 maturin 是一个用于构建和发布 Rust 编写的 Python 绑定库的工具。它简化了将 Rust 代码集成到 Python 项目中的过程,支持创建不同类型的 Python 包,如纯 Python 包、包含 **Rust (系统编程语言)**扩展模块的包等。以下为你详细介绍 maturin 的相关信息并举例…...

spring boot整合flyway实现数据的动态维护

1、简单介绍一下flyway Flyway 是一款开源的数据库版本控制工具&#xff0c;主要用于管理数据库结构的变更&#xff08;如创建表、修改字段、插入数据等&#xff09;。它通过跟踪和执行版本化的迁移脚本&#xff0c;帮助团队实现数据库变更的自动化。接下来简单介绍一下flyway…...

unity中使用spine详解

一.Spine概述 Spine 是一款针对游戏开发的 2D 骨骼动画编辑工具。 Spine 旨在提供更高效和简洁 的工作流程&#xff0c;以创建游戏所需的动画。 Spine原理&#xff1a;将一个模型&#xff0c;根据动画的需求分成一些骨骼&#xff0c;一个骨骼对应一张贴图&#xff0c;控制骨骼…...

14. LangChain项目实战1——基于公司制度RAG回答机器人

教学视频&#xff1a; 12. 基于Gradio搭建基于公司制度RAG_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV11VXRYTErZ/ 环境配置&#xff1a; python版本&#xff1a;3.10.8 服务器&#xff1a;Ubuntu 依赖包requirements.txt文件内容&#xff1a; aiofiles23.2.1 …...

利用STM32TIM自制延迟函数实验

一、实验目的 掌握STM32定时器&#xff08;TIM&#xff09;的工作原理及配置方法学习使用HAL库实现微秒级/毫秒级延时函数理解定时器中断服务程序的编写规范 二、实验原理 ​定时器基础&#xff1a; STM32定时器包含向上计数器、向下计数器、中心对齐模式通过预分频器&#x…...

CodeMirror边栏不止能显示行号:手把手教你打造代码调试器与个性化标记系统

CodeMirror边栏不止能显示行号&#xff1a;手把手教你打造代码调试器与个性化标记系统 在代码编辑器的演进历程中&#xff0c;边栏&#xff08;Gutter&#xff09;这个看似简单的区域&#xff0c;已经从单纯显示行号的辅助工具&#xff0c;进化为开发者与代码交互的重要界面。想…...

毫米波雷达开发者必看:双级联方案如何用DDMA波形实现300米精准测距?

毫米波雷达双级联方案实战&#xff1a;DDMA波形设计如何突破300米测距极限&#xff1f; 当特斯拉HW4.0的雷达模块在暴雨中依然稳定输出300米外的障碍物坐标时&#xff0c;背后的技术密码正是双级联架构与DDMA波形的完美融合。作为L3级自动驾驶系统的"全天候之眼"&am…...

告别单片机!用Multisim 10.0和74LS192芯片,手把手教你搭一个30秒倒计时器(附完整电路图)

数字电路实战&#xff1a;用Multisim与74LS192打造精准30秒倒计时器 在电子设计领域&#xff0c;倒计时器是一个经典而实用的项目。传统上&#xff0c;许多初学者会直接选择单片机方案&#xff0c;认为编程控制更为简单。但真正理解数字电路的工作原理&#xff0c;掌握硬件层面…...

从HAL_Delay到精准定时:STM32 HAL库中微秒与毫秒延时方案的深度解析与实战

1. HAL库延时函数的基本原理与局限性 在STM32开发中&#xff0c;HAL_Delay()可能是我们最早接触的延时函数。这个看似简单的函数背后&#xff0c;其实隐藏着精妙的系统设计。HAL库默认使用SysTick定时器来实现毫秒级延时&#xff0c;每次调用HAL_Delay()时&#xff0c;实际上是…...

用STM32F103C8T6和NRF24L01自制遥控器,从硬件选型到代码调试的完整避坑指南

STM32F103C8T6与NRF24L01遥控器开发实战&#xff1a;从硬件设计到软件调试的全流程解析 在创客和嵌入式开发领域&#xff0c;无线遥控系统一直是热门话题。无论是机器人控制、无人机飞行还是智能家居应用&#xff0c;稳定可靠的遥控器都是不可或缺的核心组件。本文将详细介绍如…...

保姆级教程:在Ubuntu 20.04上搞定Isaac Gym Preview 4和强化学习环境(含常见libpython报错解决)

保姆级教程&#xff1a;在Ubuntu 20.04上搞定Isaac Gym Preview 4和强化学习环境&#xff08;含常见libpython报错解决&#xff09; 刚接触Isaac Gym的机器人/强化学习新手&#xff0c;往往会在环境配置阶段遇到各种依赖问题。本文将提供一个从零开始的详细安装指南&#xff0c…...

QT6 + CMake + QML开发:你的图片和QML文件加载不出来?可能是.qrc没配对

QT6 CMake QML开发&#xff1a;资源加载失败的终极排查指南 当你花了几个小时精心设计了QML界面&#xff0c;却在运行时看到一片空白或"找不到文件"的错误提示时&#xff0c;那种挫败感每个QT开发者都深有体会。特别是在QT6和CMake的现代开发环境中&#xff0c;资源…...

新手友好!Qwen3-ASR-1.7B镜像使用全攻略:从安装到实战

新手友好&#xff01;Qwen3-ASR-1.7B镜像使用全攻略&#xff1a;从安装到实战 1. 为什么选择Qwen3-ASR-1.7B&#xff1f; 语音识别技术正在改变我们处理音频内容的方式。Qwen3-ASR-1.7B作为阿里云通义千问团队开发的开源语音识别模型&#xff0c;在识别精度和语言支持方面表现…...

Graphormer惊艳案例:从SMILES到三维构象倾向性预测的延伸应用探索

Graphormer惊艳案例&#xff1a;从SMILES到三维构象倾向性预测的延伸应用探索 1. 模型概述 Graphormer是微软研究院开发的一款基于纯Transformer架构的图神经网络模型&#xff0c;专门为分子图&#xff08;原子-键结构&#xff09;的全局结构建模与属性预测而设计。与传统图神…...

MegSpot专业视觉分析工具:从基础操作到高级应用全指南

MegSpot专业视觉分析工具&#xff1a;从基础操作到高级应用全指南 【免费下载链接】MegSpot MegSpot是一款高效、专业、跨平台的图片&视频对比应用 项目地址: https://gitcode.com/gh_mirrors/me/MegSpot 在数字媒体创作与分析领域&#xff0c;如何高效对比图片细节…...