探索5 大 Node.js 功能

news2025/1/9 15:10:44

目录

单线程 Node.js

工作线程【Worker Threads】

Node.js 进程

进程缺点

工作线程

注意

集群进程模块【Cluster Process Module】

内部发生了什么?

为什么要使用集群

注意:

应用场景:

内置 HTTP/2 支持

这个 HTTP/2 是什么?

Node.js 如何提供对 HTTP/2 的支持?

开始使用 http2

流【Streams API】

什么是流

为什么要使用 Streams?

开始使用 Streams

结论

REPL (Read-Eval-Print Loop)

介绍

命令行快捷键

结论

结论


单线程的 Node.js

首先我们要知道Node.js 以其单线程架构而闻名。
最初,Node.js 是为 I/O 密集型任务(如 Web 服务器)而设计的。对于这些任务,创建多个线程会增加管理线程同步和上下文切换的开销和复杂性。相反,Node.js 采用了事件驱动的方法。

这种行为给 Node.js 带来了一些优点,但也有局限性。

优点还行。但是局限性呢?
Node.js 单线程事件循环带来的主要限制如下,

CPU 密集型任务可能会阻塞循环:大量计算可能会“冻结”循环,从而影响其他请求的响应能力。
没有真正的并行:任务仍然一个接一个地执行,而不是同时执行。

为了解决这些限制,Node.js在各个 Node.js 版本中引入了工作线程和集群模块。

工作线程【Worker Threads

Node.js 进程

当 Node.js 进程启动时,它会运行:

  • 一个进程:进程是一个全局对象,可以在任何地方访问,并且包含有关当前正在执行的操作的信息。
  • 一个线程:单线程意味着在给定的进程中一次只执行一组指令。
  • 一个事件循环:这是了解 Node 最重要的方面之一。尽管 JavaScript 是单线程的,但它却允许 Node 异步并具有非阻塞 I/O,方法是通过回调、承诺和 async/await 尽可能将操作卸载到系统内核。
  • 一个 JS 引擎实例:这是一个执行 JavaScript 代码的计算机程序。
  • 一个 Node.js 实例:执行 Node.js 代码的计算机程序。

换句话说,Node 在单线程上运行,事件循环中一次只发生一个进程。一个代码,一次执行(代码不是并行执行的)。这非常有用,因为它简化了使用 JavaScript 的方式,而不必担心并发问题。

采用这种方法构建的原因是 JavaScript 最初是为客户端交互(如网页交互或表单验证)创建的——不需要多线程的复杂性。

进程缺点

但是,它也存在缺点:如果代码占用大量 CPU,例如在内存中进行大型数据集的复杂计算,它可能会阻止其他进程的执行。同样,如果向包含占用大量 CPU 的代码的服务器发出请求,该代码可能会阻塞事件循环并阻止处理其他请求。

如果主事件循环必须等待直到执行完下一个命令,则该函数被视为“阻塞”。 “非阻塞”函数将允许主事件循环在开始时立即继续,并且通常在主循环完成后通过调用“回调”来提醒主循环。

黄金法则:不要阻塞事件循环,尽量保持其运行,并注意避免任何可能阻塞线程的事情,如同步网络调用或无限循环。

工作线程

对于CPU性能最好的解决方案就是Worker Threads
工作线程具有:

  • 一个流程
  • 多线程
  • 每个线程一个事件循环
  • 每个线程一个 JS 引擎实例
  • 每个线程一个 Node.js 实例

工作线程可以:

  • 卸载 CPU 密集型任务:释放主线程以执行其他工作。
  • 实现并行:并发执行任务以获得更快的性能。
  • 高效共享数据:避免在进程之间复制数据的开销。

工作线程的特殊之处:

  • ArrayBuffers将内存从一个线程转移到另一个线程
  • SharedArrayBuffer可以从任一线程访问。它允许在线程之间共享内存(仅限于二进制数据)。
  • Atomics可用,它允许更高效地同时执行一些进程,并允许在 JavaScript 中实现条件变量
  • MessagePort,用于不同线程之间的通信。可用于在不同的Worker之间传输结构化数据、内存区域和其他MessagePort。
  • MessageChannel表示用于不同线程之间通信的异步、双向通信通道。
  • WorkerData用于传递启动数据。一个任意的 JavaScript 值,其中包含传递给此线程的 Worker 构造函数的数据的克隆。数据的克隆方式与使用postMessage()

API

  • const { worker, parentPort } = require(‘worker_threads’)=>worker该类代表一个独立的 JavaScript 执行线程,是parentPort消息端口的一个实例
  • new Worker(filename)或new Worker(code, { eval: true })=> 是启动 worker 的两种主要方式(传递文件名或要执行的代码)。建议在生产中使用文件名。
  • worker.on(‘message’),worker/postMessage(data)=> 用于监听消息并在不同的线程之间发送消息。
  • parentPort.on(‘message’), parentPort.postMessage(data)=> 使用 发送的消息parentPort.postMessage()将在使用 的父线程中可用worker.on('message'),并且使用 从父线程发送的消息worker.postMessage()将在使用 的本线程中可用parentPort.on('message')。

例子

const { Worker } = require('worker_threads');

const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.once('message',
    message => parentPort.postMessage({ pong: message }));  
`, { eval: true });
worker.on('message', message => console.log(message));      
worker.postMessage('ping');  
$ node --experimental-worker test.js
{ pong: ‘ping’ }

注意

  • 工作线程共享内存
  • 创建和管理工作线程会产生一些开销,因此请考虑其针对特定用例的益处与成本。
  • 线程安全至关重要!使用同步机制来确保数据完整性。
  • 工作线程增加了复杂性,因此请明智地将它们用于真正受益于并行性的任务。

集群进程模块【Cluster Process Module

该cluster模块可分散 Node.js 应用程序的工作负载,充分利用计算机(服务器)的全部处理能力。例如,如果我们有一个 8 核处理器,那么我们的工作就不必只集中在一个核心上,而是可以分散到所有八个核心上。

使用cluster,第一个核心将成为“主核心”,而所有其他核心将成为“工作核心”。当请求进入应用程序时,主进程将执行循环式检查,询问“哪个工作核心现在可以处理此请求?”满足要求的第一个工作核心将获得请求。重复此过程。

例子

const cluster = require('cluster');

if (cluster.isMaster) {
  // Master process
  const numWorkers = require('os').cpus().length;

  for (let i = 0; i < numWorkers; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(worker ${worker.process.pid} died );
  });
} else {
  // Worker process
  // Your application logic here
  app.listen(3000);
}

内部发生了什么?

集群模块创建多个独立的 Node.js 进程,每个进程都有自己的事件循环和内存空间。

这些进程在不同的核心上独立运行,利用多个核心来提高性能(水平扩展)。

它通过创建一个主进程和多个工作进程来运行。主进程管理工作进程之间传入连接的分配。如果工作进程发生故障,主进程可以重新生成一个新进程,从而确保在发生故障时的稳健性。

为什么要使用集群

  • 提高性能:处理更高的流量并改善响应时间,特别是对于 I/O 密集型任务。
  • 最大限度地提高资源利用率:充分利用服务器中所有可用的核心,显著提高处理能力。
  • 增强的容错能力:如果一个工作程序崩溃,其他工作程序仍可保持应用程序运行,确保可靠性和正常运行时间。

注意:

  • 工作进程共享内存和资源,因此请仔细考虑数据同步。
  • 集群模块增加了应用程序架构的复杂性,因此请根据特定需求评估其优势与复杂性。

应用场景:

  • 高流量网站:当单线程事件循环达到其极限时,使用集群进行水平扩展有助于有效地管理庞大的用户群。
  • 长时间运行的任务:如果某些请求涉及长时间操作(如图像处理或数据加密),则将它们分布在工作进程中可以提高其他请求的响应能力。
  • 容错至关重要:对于关键任务应用程序,集群模块对单个进程故障的恢复能力提供了宝贵的保护。

内置 HTTP/2 支持

虽然工作线程和集群模块解决了不同的问题,但 Node.js 的模块通过提供对高效HTTP/2 协议的http2内置支持直接解决性能问题。

这个 HTTP/2 是什么?

HTTP/2 是 HTTP/1.1 的后继者,它带来了多项性能增强:

  • 多路复用:支持在单个连接上同时发送和接收多个请求和响应,消除了困扰 HTTP/1.1 的队头阻塞问题。
  • 报头压缩:通过压缩来缩小报头大小,从而大幅减少数据传输开销。
  • 服务器推送:允许服务器在客户端请求资源之前主动向客户端发送资源,从而可能加快页面加载时间。

Node.js 如何提供对 HTTP/2 的支持?

Node.js 提供了一个http2用于 HTTP/2 的强大模块。以下是它提供的一些功能:

  • 创建 HTTP/2 服务器:使用熟悉的 Node.js 服务器模式以及用于管理流和服务器推送功能的附加选项。
  • 处理 HTTP/2 客户端:访问客户端功能以连接并与 HTTP/2 服务器交互。
  • 广泛的 API:探索各种方法和事件来管理连接、流、推送机制和错误处理。

开始使用 http2

Node.js 文档提供了使用 http2 模块的详细指南和示例。但是,仅提供链接是不够的。让我们通过一些实际示例来演示其用法。

1.创建一个基本的HTTP / 2服务器:

const http2 = require('http2');

const server = http2.createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'status': 200,
    'content-type': 'text/plain',
  });
  stream.end('Hello from your HTTP/2 server!');
});

server.listen(3000, () => {
  console.log('Server listening on port 3000');
});

此代码创建了一个简单的服务器,向通过 HTTP/2 连接的任何客户端发送“Hello”消息。
2.处理客户请求:

const http2 = require('http2');

const server = http2.createServer();

server.on('stream', (stream, headers) => {
  const path = headers[':path'];

  if (path === '/') {
    stream.respond({
      'status': 200,
      'content-type': 'text/plain',
    });
    stream.end('Hello from HTTP/2 server!');
  } else {
    stream.respond({
      'status': 404,
      'content-type': 'text/plain',
    });
    stream.end('Not found');
  }
});

server.listen(3000, () => {
  console.log('Server listening on port 3000');
});

此代码扩展了前面的示例,以处理不同的请求路径(/)并发送适当的响应。

流【Streams API】

Stream 是允许开发人员连续从源读取和写入数据的对象。Stream 是用于处理 Node.js 中连续数据集合的抽象接口。可读、可写、双工和转换是 Node.js 中的四种主要流类型。每个流都是一个eventEmitter实例,它会在一定时间间隔内发出不同的事件。

什么是流

想象一下数据像水流一样流动 — — 这就是本质上的概念

流的一个独特功能是它不是一次性读取内存中的所有数据,而是读取并处理小块数据。这样,就不必一次性保存和处理整个文件。

Streams 可用于构建实际应用程序,例如视频流应用程序,使用此服务,不必一次性下载所有视频或音频源,而是可以立即观看视频并收听音频。这就是浏览器以连续的块流形式接收视频和音频的方式。如果这些网站在流式传输之前先等待整个视频和音频下载完毕,则播放视频可能需要很长时间。

流基于一个称为缓冲区的概念进行工作。缓冲区是一种临时内存,用于保存数据,直到流被使用为止。

流表示随时间推移传递的连续数据块序列。Node.js 提供各种流类型,每种类型都适用于不同的用例:

  • 可读流:发出数据块以供使用,非常适合读取文件、网络连接或用户输入。
  • 可写流:允许写入数据块,非常适合写入文件、网络连接或数据库。
  • 双工流:结合读写功能,适用于套接字或管道等双向通信。
  • 转换流:在数据流过时对其进行修改,从而实现加密、压缩或数据操作。

为什么要使用 Streams?

在涉及大型数据集或连续数据流的场景中,流非常有用。它们具有以下几个优点:

  • 内存效率:它们分块处理数据,避免一次将整个数据集加载到内存中。
  • 非阻塞特性:它们不会阻塞主线程,从而使应用程序在处理数据时保持响应。
  • 灵活性:不同的流类型可满足各种数据处理需求。

开始使用 Streams

const fs = require('fs');

const readableStream = fs.createReadStream('large_file.txt');

readableStream.on('data', (chunk) => {
  console.log('Received data chunk:', chunk.toString());
});

readableStream.on('end', () => {
  console.log('Finished reading file');
});

此代码large_file.txt分块读取文件并将其记录到控制台。

结论

  • 流是允许从源读取数据并将数据写入目标的对象。
  • 可读、可写、双工和变换是 Node.js 中的四种基本流类型。
  • 管道方法是使用流的最简单、最容易的方法。
  • 链接是一种将一个流的输出连接到另一个流并创建多个流的操作链的机制。
  • 可读流中最重要的事件是数据事件和结束事件。
  • 可写流中最重要的事件是耗尽事件和完成事件。
  • 可读流可以操作流动心情或者暂停心情。

REPL (Read-Eval-Print Loop)

REPL 是Read Evaluate Print Loop的缩写,它是一种编程语言环境(本质上是一个控制台窗口),它接受单个表达式作为用户输入,执行该表达式,并在执行后将结果返回到控制台。REPL 会话允许快速测试和执行基本的 JavaScript 程序。可以在 REPL 上轻松测试代码的独立部分。

想象一个沙盒环境,可以在其中试验代码片段、测试想法并获得即时反馈 - 这就是 REPL 的本质。

介绍

REPL(READ、EVAL、PRINT、LOOP)是相当于Unix/Linux中Shell的命令行环境。Node在安装时自带REPL环境。系统通过显示其执行的指令的结果来与用户通信。它对于开发和调试过程都很方便。REPL的所有部分都有特定的任务。

  • 读取:读取用户提供的输入。经过必要的解析后,将信息保存在内存中。
  • Eval:对解析信息后的数据结构进行求值,并生成结果。
  • 打印:将评估后生成的结果显示给用户。
  • 循环:以上三个步骤全部循环,直到用户按两次ctrl+c退出循环。

每个 Node.js 安装都附带 REPL,允许即时测试和探索 JavaScript 代码,而无需将其保存在文件中。

将其视为一种对话式编码体验。输入代码表达式,REPL 会对其进行评估并显示结果,可以快速迭代和学习。这使得 REPL 在以下方面具有无价的价值:

  • 学习和实验:在安全、隔离的环境中尝试新的 JavaScript 功能、探索库并测试假设。
  • 调试和故障排除:逐行隔离和修复代码中的问题,检查每一步的变量和值。
  • 交互式开发:快速对想法进行原型设计,获得即时反馈,并迭代优化代码。
  • 访问 REPL:

打开终端并输入 node。瞧!您现在已进入 REPL,可以开始游戏了。输入任何 JavaScript 变量赋值、函数调用,甚至是复杂的计算。

$ node


Welcome to Node.js v20.11.0.
Type ".help" for more information.
> Math.random()
0.6148448277159013


> "Hello"+ " "  + "World"
'Hello World'

> 1 + 2 - 5 * (6 / 8) + 10
9.25

> var x = 10
undefined
> var y = 5
undefined
> z = 40
40
> x * y
50

与前面概述的所有强大功能相比,REPL 似乎看似简单。然而,只有通过亲身体验,它的真正价值才会显现出来。作为 Node.js 开发人员,接受 REPL 并将其集成到您的工作流程中不仅有益,而且必不可少。

命令行快捷键

CommandsDescription
向上/向下 键它用于查看命令历史记录和修改以前的命令
ctrl + d它终止节点 repl
ctrl + c它用于终止当前命令
ctrl + c  两次它终止节点 repl
tab 键它指定当前命令的列表

结论

  • REPL 是 Read Evaluate Print Loop的缩写,它是一种编程语言环境,它接受单个表达式作为用户输入,执行它,并在执行后将结果返回到控制台。
  • 您可以通过在 shell/控制台上输入node来启动 REPL。
  • REPL 允许您快速测试和评估 JavaScript 代码,而无需将其保存在文件中。
  • REPL 提供了一些快捷方式,尽可能减少编写命令所需的时间。
  • REPL 的行为可以通过某些命令(如.break、.clear、.help等)控制。
  • 你可以在 REPL 中写入算术表达式,然后按下 Enter 键即可得到计算结果。
  • 您可以以与在 javascript 文件中相同的方式在 REPL 中定义变量。

结论

在 Node.js 提供的强大工具库中,工作线程可处理 CPU 密集型任务,集群模块可实现水平扩展,http2可提供 HTTP/2 网络协议的强大功能,流可提供高效的数据处理,REPL可实现交互式探索和学习。

通过掌握这些功能,您将释放 Node.js 的全部潜力并构建高性能、可扩展且令人愉快的开发体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenHarmony(鸿蒙南向)——平台驱动指南【PWM】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 PWM即脉冲宽度调制&#xff08;Pulse Width Modul…

【Linux】部署 flask

文章目录 一、安装Python3环境二、将本地开发环境的依赖项目生成清单文件三、创建虚拟环境启用虚拟环境退出虚拟环境 四、添加自定义系统服务(很重要) 一、安装Python3环境 1.首先安装编译环境(后续需要从python官网获取Python3的源码自己编译python yum install zlib-devel …

案例研究丨国控星鲨利用DataEase释放数据潜能,重塑业务视野

国药控股星鲨制药&#xff08;厦门&#xff09;有限公司&#xff08;以下简称为国控星鲨&#xff09;始创于1952年&#xff0c;前身为厦门鱼肝油厂&#xff0c;距今已经有70余年历史&#xff0c;是国家商务部认定的“中华老字号”企业。2011年&#xff0c;国药控股与厦门轻工集…

C# C++ 笔记

第一阶段知识总结 lunix系统操作 1、基础命令 &#xff08;1&#xff09;cd cd /[目录名] 打开指定文件目录 cd .. 返回上一级目录 cd - 返回并显示上一次目录 cd ~ 切换到当前用户的家目录 &#xff08;2&#xff09;pwd pwd 查看当前所在目录路径 pwd -L 打印当前物理…

从“可用”到“好用”,百度智能云如何做大模型的“超级工厂”?

如果说&#xff0c;过去两三年大模型处于造锤子阶段&#xff0c;那么今年&#xff0c;更多的则是考验钉钉子的能力&#xff0c;面对各类业务场景大模型是否能够有的放矢、一击必中&#xff0c;为千行百业深度赋能。 当前市场上&#xff0c;已经有200多把这样的锤子在疯狂找钉子…

从零开始使用树莓派debian系统使用opencv4.10.0进行人脸识别(保姆级教程)

一、总体架构 本文主要是使用树莓派自带的csi摄像头&#xff0c;搭配上opencv4.10.0进行物体的识别。本文使用的环境是python3.7.3&#xff0c;环境不一样有可能安装的opencv的过程也会很不一样&#xff0c;但是python的环境我们可以自己自行安装。 二、树莓派系统的安装 本文…

江协科技STM32学习- P19 TIM编码器接口

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

亲身体验Llama 3.1:开源模型的部署与应用之旅

文章目录 1 Llama 3.1系列的诞生2 大型模型的未来发展3 使用教程4 Llama 3.1在客户服务中的运用 1 Llama 3.1系列的诞生 在人工智能的浪潮中&#xff0c;大型语言模型&#xff08;LLM&#xff09;正以其独特的魅力和潜力&#xff0c;成为深度学习领域的一颗耀眼明星。 这些模…

计算机毕业设计Hadoop+Spark知识图谱体育赛事推荐系统 体育赛事热度预测系统 体育赛事数据分析 体育赛事可视化 体育赛事大数据 大数据毕业设计

《HadoopSpark知识图谱体育赛事推荐系统》开题报告 一、研究背景及意义 随着互联网技术的迅猛发展和大数据时代的到来&#xff0c;体育赛事数据的数量呈爆炸式增长。用户面对海量的体育赛事信息&#xff0c;常常感到信息过载&#xff0c;难以快速找到感兴趣的赛事内容。如何高…

锐捷—NAT地址映射+IPsec隧道

任务目标 在出口路由器R3上将R5私网地址1对1映射的公网地址与R1建立IPsec隧道&#xff0c;使得R4在访问R5的映射公网地址时&#xff0c;可以进行IPsec隧道的转发 要求&#xff1a; 1、R4和R5可通过NAT转换正常访问互联网地址&#xff08;R2的lo0&#xff09; 2、R5的私网地…

云手机群控怎么用?有什么优势?

群控系统&#xff0c;顾名思义&#xff0c;是用于批量控制多部手机的工具&#xff0c;能够通过计算机或客户端同时管理多台设备。借助群控系统&#xff0c;用户可以在电脑上操作多部手机&#xff0c;模拟真实操作场景&#xff0c;从而大幅提升工作效率&#xff0c;并有效控制管…

calibre-web默认左上角字体修改

calibre-web默认左上角字体修改 如图&#xff1a; 有些奇异&#xff0c;如果想变成正常的常规字体&#xff0c;需要修改&#xff1a; cps\static\css\style.css 下的代码&#xff1a; 默认是GrandHotel-Regular&#xff1a; 换成其他字体即可。其他字体在 calibre-web\cps\s…

图像处理04

图像处理 问题&#xff1a;把不规则的图片按照参考图摆放 步骤&#xff1a; 1. 用ORB找关键点 2. 关键点匹配 3. 根据上一步匹配的关键点得出单应性矩阵 4. 根据单应性矩阵对不规则进行透视变换 import cv2 import numpy as np import matplotlib.pyplot as pltimgl cv2.imrea…

微信小程序 - 最新详细安装使用 Vant weapp UI 框架环境搭建详细教程

前言 自从 2024 年开始,小程序做了很多改变和升级, 导致网上很多搭建教程文章的教程失效了,本文来做最新的教程。 第一步 为了更贴合新手,我这里创建了一个纯净无任何业务代码的小程序项目。

【AI基础】pytorch lightning 基础学习

传统pytorch工作流是首先定义模型框架&#xff0c;然后写训练和验证&#xff0c;测试循环代码。训练&#xff0c;验证&#xff0c;测试代码写起来比较繁琐。这里介绍使用pytorch lightning 部署模型&#xff0c;加速模型训练和验证&#xff0c;记录。 准备工作 1 安装pytorch…

铨顺宏科技携RTLS+RFID技术亮相工博会!

中国国际工业博览会盛大开幕&#xff01; 铨顺宏科技展亮点速递 铨顺宏科技展位号&#xff1a;F117 中国国际博览会今日开幕&#xff0c;铨顺宏科技携创新产品亮相&#xff0c;吸引众多参观者。 我们珍视此次国际盛会&#xff0c;将全力以赴确保最佳体验。 工作人员热情解答…

实时数字人DH_live使用案例

参看: https://github.com/kleinlee/DH_live ubuntu 测试 apt install ffmpeg 下载安装: git clone https://github.com/kleinlee/DH_live.git cd DH_liveconda create -n dh_live python=3.12 conda activate dh_live pip install -r requirements.txt pip install torch -…

E. Alternating String

E. Alternating String 这道题就是前缀和的变化, 现在做起来比较简单, 打这场的时候差了点时间就做出来了 代码 #include <bits/stdc.h> #define int long long using namespace std;const int N 200010;int od[N][30], ev[N][30]; int n;void init() {for(int i 0; …

【Linux篇】常用命令及操作技巧(进阶篇 - 上)

&#x1f30f;个人博客主页&#xff1a;意疏-CSDN博客 文章目录&#xff1a; Linux常用命令以及操作技巧&#xff08;进阶&#xff09;前言一、远程管理常用命令1、关机/重启shutdown命令 二、查看或配置网卡信息2、网卡和IP地址网卡IP地址ifconfig命令ping命令 三、SSH基础1.…

Dart中FFI学习

Flutter中FFI学习 Dart FFI编程概述NativeType&#xff08;类型映射&#xff09;Window安装GCCDart调用C的函数数组字符串结构体 Dart FFI编程 概述 dart:ffi库可以使用Dart语言调用本地C语言API ,并读取、写入、分配和删除本地内存。FFI是指外部函数接口&#xff08;Foregin…