写一个类ChatGPT应用,前后端数据交互有哪几种

news2024/12/24 22:05:23

对世界的态度,本质都是对自己的态度

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

最近,公司有一个AI项目,要做一个文档问答的AI产品。前端部分呢,还是「友好借鉴」ChatGPT。别问为什么,问就是要站在巨人的肩膀上进行「带有中国特色」的创新。而后端是接入我们团队的模型,我咨询过模型团队,也是基于开源模型做参数的微调,这个魔幻的世界真让人欲罢不能。这就是大概的业务背景。

针对前端部分,其实没啥可聊的,就是接入模型返回的数据然后进行展示处理。大家以为这就是一个简单到令人发指的功能时。有一个点却映入眼帘,如何才能实现类似ChatGPT结果展示效果(逐步输出结果,类似打字效果)。也就是在结果返回的时候,如何做打字效果。

此外,还有一个大背景就是,由于需求是可能要上传多个文件,并且模型那边的操作可能对文档解析有一定的难度。所以,在客户端发起请求时,可能投喂给模型的物料有点多,返回的结果的时间也会很长。也就是如果处理不当的话,在结果没返回之前或者一股脑把结果处理完再返回的话,前端会有一段很长的等待时间。

从上面的需求点和解决方案,我们不难看出,其实结果的展示(打字效果)不是一个难点,我们可以借助简单的库或者手搓一个打字效果都是可以的,而是数据的获取制约我们应用响应。

我们又可以按照数据的发起方是谁(客户端/服务端)

  1. 基于最原始的数据获取方式,客户端发起请求,服务端接入模型数据并返回,然后前端一股脑把所以结果都接入。
  2. 数据的发起方是服务端,然后在有合适的数据时,就将其发布给客户端,前端接收到数据后就进行结果的显示。此处我们可以按照流式将数据返回

所以,这又引起了另外一个问题,前后端数据交互我们应该采用何种方式。其实针对,后端主动发起数据的方式我们有很多方案

  • 长轮询(Long-Polling)
  • WebSockets
  • 服务器发送事件(Server-Sent Events,SSE)
  • WebRTC
  • WebTransport

那我们到底用哪种方式亦或者说它们都是个啥,都有啥优缺点。所以,今天我们来用一篇文章来讲讲它们直接的区别和联系。

好了,天不早了,干点正事哇。

alt

我们能所学到的知识点

  1. 长轮询(Long-Polling)
  2. WebSockets
  3. 服务器发送事件( SSE)
  4. WebTransport
  5. WebRTC
  6. 技术的限制
  7. 性能比较
  8. 适用场景

1. 长轮询(Long-Polling)

长轮询可以在浏览器上通过 HTTP 启用一种服务器-客户端消息传递方法。该技术通过普通的 XHR 请求模拟了服务器推送通信。与传统的轮询不同,其中客户端会在「固定的时间间隔内重复向服务器请求数据」,长轮询建立了一条连接到服务器的连接,该连接保持打开状态,直到有新数据可用为止。一旦服务器有了新信息,就会将响应发送给客户端,并关闭连接。

在接收到服务器的响应后,客户端立即发起新的请求,这个过程会重复进行。这种方法允许「更即时地更新数据,并减少不必要的网络流量和服务器负载」。然而,它仍然可能引入通信延迟,并且不如其他实时技术(如 WebSockets)高效。

function longPoll({
  fetch('http://front789.com/poll')
    .then(response => response.json())
    .then(data => {
        console.log("接收到的数据:", data);
        longPoll(); // 立即发起新的长轮询请求
    })
    .catch(error => {
        /**
        * 在正常情况下可能会出现错误,
        * 当连接超时或客户端离线时。
        * 出现错误时,我们会在一段延迟后重新启动轮询。
        */

        setTimeout(longPoll, 10000);
    });
}
longPoll(); // 初始化长轮询

长轮询解决了在网络平台上构建双向应用程序的问题,也就是我们经常用的模式- 「客户端发出请求,服务器响应」。这是通过颠覆请求-响应模型来实现的:

  1. 客户端服务器发送 GET 请求:与传统的 HTTP 请求不同,我们可以将其视为开放式的。它不是请求特定的响应,而是在准备好时请求任何响应。
  2. 请求时间设置: HTTP 超时可以使用 Keep-Alive 头进行调整。
    • 长轮询利用此功能,通过设置非常长或无限期的超时时间,使请求保持打开状态,即使服务器没有立即响应。
  3. 服务器响应:当服务器有要发送的内容时,它会使用响应关闭连接。
    • 返回的数据可以是新的 聊天消息体育比分突发新闻等。
  4. 客户端发送新的 GET 请求,循环重新开始。
alt

2. WebSockets

WebSockets[1] 是一种实时技术,可通过持久的单套接字(socket)连接在客户端和服务器之间实现「双向全双工通信」WebSockets 相对于传统的 HTTP,代表了一个重大进步,因为一旦建立连接,双方就可以「独立发送数据」,这使其非常适合需要低延迟和高频更新的场景。

WebSocket 技术由两个核心构建块组成:

  • WebSocket协议: WebSocket是建立在 TCP协议之上的一种 「应用层协议」。该协议旨在允许客户端和服务器 「实时通信」,从而在 Web 应用程序中实现高效且响应迅速的数据传输。
  • WebSocket API: WebSocket API 是一个编程接口,用于创建 WebSocket 连接并管理 Web 应用程序中客户端和服务器之间的数据交换。几乎所有现代浏览器都支持 WebSocket API alt

如何工作的

概括地说,使用 WebSockets 涉及三个主要步骤:

  1. 打开 WebSocket 连接
    • 建立 WebSocket 连接的过程称为 握手,由客户端和服务器之间的 HTTP 请求/响应交换组成。
  2. 通过 WebSockets 传输数据
    • 成功打开握手后,客户端和服务器可以通过持久 WebSocket 连接交换消息(帧)。 WebSocket 消息可能包含字符串(纯文本)或二进制数据。
  3. 关闭 WebSocket 连接。
    • 一旦持久的 WebSocket 连接达到其目的,它就可以终止;
    • 客户端和服务器都可以通过发送关闭消息来启动关闭握手。
alt
// 创建 `WebSocket` 连接
const socket = new WebSocket("ws://localhost:7899");

// 打开链接,并发送信息
socket.addEventListener("open", (event) => {
  socket.send("Hello Front789!");
});

// 监听来自服务端的数据
socket.addEventListener("message", (event) => {
  console.log("来自服务端的数据", event.data);
});
// 关闭链接
socket.onclose = function(e{
   console.log("关闭链接", e);
};

虽然 WebSocket API 的基础用法很容易,但在生产环境中却相当复杂。一个 socket 可能会断开连接,必须相应地重新创建。特别是检测连接是否仍然可用或不可用可能会非常棘手。通常,我们会添加一个 ping-and-pong[2] 心跳以确保打开的连接不会关闭。我们可以借助类似像 Socket.IO[3] 这样的库来处理重连的情况,需要时提供了以「长轮询」为回退方案。

想了解更多关于WebSocket可以参考The WebSocket API and protocol explained[4]


3. 服务器发送事件(SSE)

服务器发送事件(Server-Sent EventsSSE)提供了一种标准方法,通过 HTTP 将服务器数据推送到客户端。与 WebSockets 不同,SSE 专门设计用于「服务器到客户端的单向通信」,使其非常适用于实时信息的更新或者那些在不向服务器发送数据的情况下实时更新客户端的情况。

我们可以将服务器发送事件视为单个 HTTP 请求,其中后端不会立即发送整个主体,而是保持连接打开,并通过每次发送事件时发送单个行来逐步传输答复。

alt

SSE是一个由两个组件组成的标准:

  1. 浏览器中的 EventSource 接口,允许客户端订阅事件:它提供了一种通过抽象较低级别的连接和消息处理来订阅事件流的便捷方法。
  2. 事件流协议:描述服务器发送的事件必须遵循的标准纯文本格式,以便 EventSource 客户端理解和传播它们

在浏览器的客户端上,我们可以使用服务器端生成事件脚本的 URL 初始化一个 EventSource[5] 实例。

// 连接到服务器端事件流
const evtSource = new EventSource("https://front789.com/events");

// 处理通用消息事件
evtSource.onmessage = event => {
    if(event.data.trim() !== 'undefined'){
    const newData = event.data;
    // 数据追加
    setResponse((prevResponse) => prevResponse.concat(newData));
  } else{
    // 当从服务端接收到值为`undefined`的数据时,关闭链接
    setTempPrompt(''); 
    eventSource.close();
  }
};

WebSockets 不同,EventSource 在连接丢失时会自动重新连接。

在服务器端,我们的脚本必须将 Content-Type 标头设置为 text/event-stream,并根据 SSE 规范[6]格式化每条消息。这包括指定事件类型数据有效负载可选字段,如事件 ID

以下是使用Node.js Express处理SSE的示例:

import express from 'express';
const app = express();
const PORT = process.env.PORT || 7890;

const headers = {
    'Content-Type''text/event-stream',
    'Connection''keep-alive',
    'Cache-Control''no-cache'
}

app.get('/events', (req, res) => {
    res.writeHead(200, headers);

    const sendEvent = (data) => {
        // 所有数据都必须以'data:'开头
        const formattedData = `data: ${JSON.stringify(data)}\n\n`;
        res.write(formattedData);
    };

    // 每两秒发送一个事件
    const intervalId = setInterval(() => {
        const message = {
            timenew Date().toTimeString(),
            message'服务端产生的数据',
        };
        sendEvent(message);
    }, 2000);

    // 关闭轮询
    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

文章最开始,我们不是说想实现实时响应后端返回并且逐字显示聊天机器人回复,我们其实就可以使用SSE的方案。而ChatGPT也是使用这个机制实现的。


4. WebTransport

WebTransport[7] 是一个专为 Web 客户端和服务器之间进行高效、低延迟通信而设计的前沿 API。它利用了 HTTP/3 QUIC 协议[8],可以实现以可靠不可靠的方式实现多个流的数据传输功能,甚至允许数据无序发送。这使得 WebTransport 成为需要高性能网络的应用程序的强大工具,如实时游戏、直播和协作平台。但是,值得注意的是,WebTransport 目前是一个工作草案,尚未被广泛采用。 alt

截至目前(2024 年 5 月),WebTransport 仍处于工作草案阶段[9],并没有得到广泛支持。 alt

目前还不能在 Safari 浏览器中使用 WebTransport,而且 Node.js 也没有原生支持。这限制了其在不同平台和环境中的可用性。


5. WebRTC

网页实时通信(Web Real-time Communication,WebRTC)[10]是一个增强网页浏览模式。它允许浏览器通过安全访问输入设备(如网络摄像头麦克风),以「点对点的方式直接与其他浏览器交换实时媒体数据」

WebRTC 既是 API 又是协议。

  • WebRTC 协议是一组规则,供两个 WebRTC 代理协商双向安全实时通信。
  • WebRTC API 允许开发人员使用 WebRTC 协议。 WebRTC API 仅针对 JavaScript

传统的网页架构是基于客户端-服务器模型,客户端发送HTTP请求到服务器并获得包含所请求信息的响应。与此相对,WebRTC允许N个实体之间交换数据。在这种交换中,实体彼此直接通信,而无需中间服务器。

WebRTC内置于HTML 5,因此我们不需要第三方软件或插件即可使用它,我们可以通过WebRTC API在浏览器中访问它。它支持浏览器之间的音频视频和数据流交换的点对点连接。WebRTC 设计用于通过 NAT 和防火墙工作,利用诸如 ICESTUNTURN 等协议来建立对等之间的连接。

alt

虽然 WebRTC 是为客户端-客户端交互设计的,但也可以利用它进行服务器-客户端通信,其中「服务器只是模拟成一个客户端」。这种方法只适用于特定的用例,问题在于,要使 WebRTC 正常工作,我们仍然需要一个服务器,这个服务器会再次通过 WebSocketsSSEWebTransport 运行。这就背离了使用 WebRTC 作为这些技术的替代方案的初衷。


6. 技术的限制

双向发送数据

只有 WebSocketsWebTransport「双向全双工通信」,这样我们就可以在同一个连接上接收服务器数据并发送客户端数据。

虽然理论上使用长轮询也是可能的,但并不建议,因为向现有的长轮询连接发送“新”数据实际上还是需要额外的 HTTP 请求。因此,我们可以通过额外的 HTTP 请求直接将数据从客户端发送到服务器,而不会中断长轮询连接。

SSE不支持向服务器发送任何附加数据。我们只能进行初始请求,即使在原生的 EventSource API 中,默认情况下也无法在 HTTP 主体中发送类似 POST 的数据。相反,我们必须将所有数据放在 URL 参数中,这被认为是一种不安全的做法,因为凭据可能会泄漏到服务器日志、代理和缓存中。

每个域的 6 个请求限制

大多数现代浏览器允许「每个域最多六个连接」这限制了服务器-客户端消息传递方法的可用性。这六个连接的限制甚至在浏览器选项卡之间共享,因此当我们在多个选项卡中打开相同的页面时,它们必须彼此共享六个连接池。

虽然这个策略可以防止D-DOS 攻击,但当多个连接是为了处理合法的通信时,它可能会造成很大的问题。为了解决这个限制,我们必须使用 HTTP/2HTTP/3,其中浏览器为每个域只会打开一个连接,然后使用「多路复用」来通过单个连接传输所有数据。虽然这样可以给我们几乎无限量的并行连接,但有一个 SETTINGS_MAX_CONCURRENT_STREAMS[11] 设置,它限制了实际的连接数量。对于大多数配置,默认值为 100 个并发流。

在移动应用程序中不保持连接

AndroidiOS 等操作系统上运行的移动应用程序中,保持打开连接(例如 WebSockets 和其他连接)会带来很大的挑战。移动操作系统被设计为「在一段时间的不活动后自动将应用程序移至后台,从而有效关闭任何打开的连接」。这种行为是操作系统资源管理策略的一部分,旨在节省电池并优化性能。因此,我们通常依赖于移动推送通知作为一种高效可靠的方法,以将数据从服务器发送到客户端。推送通知允许服务器提醒应用程序有新数据到达,促使执行某个操作或更新,而无需保持持续的打开连接。


7. 性能比较

对于一些我们平时可能会用到的技术例如WebSocketsSSE长轮询WebTransport 我们可以从延迟、吞吐量、服务器负载和在不同条件下的可伸缩性的角度来比较。

延迟

  • WebSockets:由于其通过单个持久连接进行全双工通信,提供了最低的延迟。适用于实时应用程序,其中立即数据交换至关重要。
  • SSE:也提供了低延迟的服务器到客户端通信,但不能直接发送消息回服务器,需要额外的 HTTP 请求。
  • 长轮询:由于依赖于为每个数据传输 「建立新的 HTTP 连接」,因此产生较高的延迟,使其对实时更新不太有效。此外,当服务器希望在客户端仍在打开新连接的过程中发送事件时,可能会出现延迟显著较大的情况。
  • WebTransport:承诺提供类似于 WebSockets 的低延迟,同时利用 HTTP/3 协议进行更高效的多路复用和拥塞控制。

吞吐量

  • WebSockets:由于其持久连接,能够实现高吞吐量,但当客户端无法处理数据时,吞吐量可能会受到反压的影响, 反压 [12]是指客户端无法处理服务器发送的数据速度。
  • SSE:对于向客户端广播消息而言,效率高于 WebSockets,开销较小,因此在单向的服务器到客户端通信中可能会实现更高的吞吐量。
  • 长轮询:由于频繁打开和关闭连接的开销较大,通常提供较低的吞吐量,这会 「消耗更多的服务器资源」
  • WebTransport:支持单个连接内的双向和单向数据流的高吞吐量,性能优于需要多个流的场景下的 WebSockets

可伸缩性和服务器负载

  • WebSockets:维护大量 WebSocket 连接可能会显著增加服务器负载,可能影响具有许多用户的应用程序的可伸缩性。
  • SSE:对于主要需要来自服务器到客户端的更新的场景,更具可伸缩性,因为与 WebSockets 相比,它使用的连接开销更小,因为它使用的是常规的 HTTP 请求,而不是像 WebSockets 那样需要运行协议更新的请求。
  • 长轮询:由于频繁建立连接产生的高服务器负载,所以是最不可伸缩的,通常仅适用于作为 「后备机制」
  • WebTransport:设计为高度可伸缩,受益于 HTTP/3 在处理连接和流时的高效性,与 WebSocketsSSE 相比,可能减少服务器负载。

8. 适用场景

服务器-客户端通信技术的领域中,每种技术都有其独特的优势和适用用例。SSE是最简单的实现选项,利用与传统 Web 请求相同的 HTTP/S 协议,因此可以规避企业防火墙限制和其他可能出现的技术问题。它们很容易集成到 Node.js 和其他服务器框架中,因此非常适合需要频繁服务器到客户端更新的应用程序,如新闻源、股票行情和实时事件流。

另一方面,WebSockets 在需要持续的双向通信的场景中表现出色。它们支持连续互动的能力,使其成为浏览器游戏、聊天应用程序和实时体育更新的首选。

然而,WebTransport 虽然潜力巨大,但面临着采用挑战。它在包括 Node.js 在内的服务器框架中得到的支持不广泛,并且与 Safari 不兼容。此外,它对 HTTP/3 的依赖进一步限制了其即时适用性,因为许多 Web 服务器(如 nginx)只有实验性的 HTTP/3 支持。虽然在支持可靠和不可靠数据传输的未来应用程序中有所希望,但在大多数用例中,WebTransport 还不是一个可行的选择。

长轮询曾经是一种常见的技术,但由于其效率低下和频繁建立新的 HTTP 连接的高开销,现在已经大大过时。虽然它可以作为没有对 WebSocketsSSE 进行支持的环境的后备方案,但由于存在显著的性能限制,通常不建议使用。


后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」

alt

Reference

[1]

WebSockets: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

[2]

ping-and-pong: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets

[3]

Socket.IO: https://socket.io/

[4]

The WebSocket API and protocol explained: https://ably.com/topic/websockets

[5]

EventSource: https://developer.mozilla.org/en-US/docs/Web/API/EventSource

[6]

SSE 规范: https://www.w3.org/TR/2012/WD-eventsource-20120426/

[7]

WebTransport: https://www.w3.org/TR/webtransport/

[8]

HTTP/3 QUIC 协议: https://en.wikipedia.org/wiki/HTTP/3

[9]

工作草案阶段: https://w3c.github.io/webtransport/

[10]

网页实时通信(Web Real-time Communication,WebRTC): https://webrtc.org/?hl=zh-cn

[11]

SETTINGS_MAX_CONCURRENT_STREAMS: https://www.rfc-editor.org/rfc/rfc7540#section-6.5.2

[12]

反压: https://chromestatus.com/feature/5189728691290112

本文由 mdnice 多平台发布

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

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

相关文章

经典神经网络(8)GAN、CGAN、DCGAN、LSGAN及其在MNIST数据集上的应用

经典神经网络(8)GAN、CGAN、DCGAN、LSGAN及其在MNIST数据集上的应用 1 GAN的简述及其在MNIST数据集上的应用 GAN模型主导了生成式建模的前一个时代,但由于训练过程中的不稳定性,对GAN进行扩展需要仔细调整网络结构和训练考虑,因此GANs虽然在…

【js逆向】易车网JS逆向案例实战手把手教学(附完整代码)

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

一表捋清网络安全等级保护测评要求

三级网络安全等级保护测评指标: 对于中小企事业单位来说,网络安全建设是一个复杂且投入较高的过程,因此他们更倾向于寻找一种“省心省力”的等保建设方案,以及一种能够持续有效且具有较高性价比的网络安全建设投入方式。 此时&…

合合信息:TextIn文档解析技术与高精度文本向量化模型再加速

文章目录 前言现有大模型文档解析问题表格无法解析无法按照阅读顺序解析文档编码错误 诉求文档解析技术技术难点技术架构关键技术回根溯源 文本向量化模型结语 前言 随着人工智能技术的持续演进,大语言模型在我们日常生活中正逐渐占据举足轻重的地位。大模型语言通…

通过java将数据导出为PDF,包扣合并单元格操作

最近项目中需要将查询出来的表格数据以PDF形式导出&#xff0c;并且表格的形式包含横向行与纵向列的单元格合并操作&#xff0c;导出的最终效果如图所示&#xff1a; 首先引入操作依赖 <!--导出pdf所需包--><dependency><groupId>com.itextpdf</groupId&…

Linux 生态与工具

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 Linux生态简介:Linux工具lrzsz&#xff…

适用于 Windows 8/10/11 的 10 大 PC 迁移工具:电脑克隆迁移软件

当您发现自己拥有一台新的 PC 或笔记本电脑时&#xff0c;PC 迁移变得至关重要。将数据从旧计算机传输到新计算机的过程似乎令人生畏&#xff0c;尤其是如果您是第一次这样做。迁移过程中数据丢失的潜在风险加剧了焦虑。为确保文件和系统设置的无缝无忧传输&#xff0c;使用专为…

探索设计模式的魅力:机器学习赋能,引领“去中心化”模式新纪元

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 探索设计模式的魅力&#xff1a;机器学习赋能&#xff0c;引领“去中心化”模式新纪元 ✨欢迎加入…

3月份太阳镜行业线上市场销售数据分析

在消费者行为方面&#xff0c;太阳镜不仅仅是视力保护工具&#xff0c;更逐渐成为一种时尚单品。随着人们对健康和美容重视程度的提高&#xff0c;太阳镜作为体现个人风格的单品&#xff0c;其市场需求得到了进一步的推动。此外&#xff0c;全球旅行和旅游业的恢复&#xff0c;…

被暗示离职?教你优雅反击

在职场中&#xff0c;面对公司暗示离职的情况&#xff0c;应届毕业生可能会感到困惑与无助。但是&#xff0c;保持冷静和据理力争是保护自己权益的重要途径。以下是如何应对此类情况的一些建议。 当你感觉到被暗示离职时&#xff0c;首要的策略就是与上司进行有效沟通。安排一个…

halo博客--解决恶意刷评论的问题

原文网址&#xff1a;halo博客--解决恶意刷评论的问题_IT利刃出鞘的博客-CSDN博客 简介 本文介绍halo博客如何通过设置评论次数来解决恶意刷评论的问题。 评论功能要设置频率的限制&#xff0c;否则可能被人一直刷评论&#xff0c;然后数据库存的垃圾评论越来越多&#xff0…

数据结构——队列(链表实现)

一、队列的特点 先进先出 二、队列的代码 typedef int QDataType;// 链式结构&#xff1a;表示队列 typedef struct QListNode {struct QListNode* next;QDataType data; }QNode;// 队列的结构 typedef struct Queue {QNode* front; //指向队列的第一个结点QNode* rear;//指…

刷代码随想录有感(66):回溯算法——组合问题的优化(剪枝)

代码&#xff1a;将for循环中i的搜索范围进行缩小&#xff0c;免去多余的不可能符合条件的操作。 for(int i start; i < n-(k-tmp.size())1;i) 实质是剪枝&#xff0c;拿n4,k4作比较&#xff1a; 显然结果只可能是[1,2,3,4]&#xff0c;选取顺序只可能是1-2-3-4&#xff…

Day27 代码随想录打卡|栈与队列篇---删除字符串中的所有相邻重复项

题目&#xff08;leecode T1047&#xff09;&#xff1a; 给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&#xff0c;直到无法继续删除。 在完成所有重复项删除操作后返回最终…

霍廷格电源 Tru plasma DC3030 通快DC3040 MF3030

霍廷格电源 Tru plasma DC3030 通快DC3040 MF3030

Muse论文精读

Muse Abstract 我们介绍了Muse&#xff0c;一个文本到图像的Transformer模型&#xff0c;它实现了最先进的图像生成性能&#xff0c;同时比扩散或自回归模型更有效。Muse是在离散标记空间中的掩码建模任务上进行训练的:给定从预训练的大型语言模型(LLM)中提取的文本嵌入&…

C语言如何删除表中指定位置的结点?

一、问题 如何删除链表中指定位置的结点&#xff1f; 二、解答 删除链表中指定的结点&#xff0c;就像是排好队的⼩朋友⼿牵着⼿&#xff0c;将其中⼀个⼩朋友从队伍中分出来&#xff0c;只需将这个⼩朋友的双⼿从两边松开。 删除结点有两种情况&#xff1a; &#xff08;1&am…

三菱FX3U-4AD模拟量电压输入采集实例

硬件&#xff1a;&#xff30;&#xff2c;&#xff23;模块 &#xff26;&#xff38;&#xff13;&#xff27;&#xff21;-&#xff12;&#xff14;&#xff2d;&#xff34; &#xff1b;&#xff21;&#xff0f;&#xff24;模块&#xff26;&#xff38;&#xff13…

连接虚拟机的 redis

用Windows 的 Redis Insight 连接虚拟机的 安装redis发现连不上 我的redis是新安装&#xff0c;没有用户名密码&#xff0c;发现是ip问题 127 开头的被我注释了&#xff0c;换成了ifconfig查到的ip

Nginx 生产环境部署的最佳实践

你好呀&#xff0c;我是赵兴晨&#xff0c;文科程序员。 最近一段时间&#xff0c;我一直在和大家一起探讨Nginx的相关话题。期间&#xff0c;我收到了很多小伙伴的私信&#xff0c;他们好奇地问我&#xff1a;在生产环境中&#xff0c;Nginx应该如何配置&#xff1f; 他们在…