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

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

大家好,我是「柒八九」。一个「专注于前端开发技术/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 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧公厕系统:改变“上厕所”体验的科技革新

公共厕所是城市建设中不可或缺的基础设施,然而,由于较为落后的管理模式,会常常存在着管理不到位、脏乱差的问题。为了改善公厕的使用体验,智慧公厕系统应运而生,并逐渐成为智慧城市建设的重要组成部分。本文将以智慧公…

德昂信息-Wyn助力构建HR人员信息分析看板

”葡萄城的Wyn商业智能软件产品为德昂信息提供了强大的支持,借助Wyn商业智能软件,可以通过可视化方式展示整个公司的人员信息及其分析看板。“ ——德昂信息技术(北京)有限公司 公司简介 德昂信息技术(北京)有限公司(以下简称德昂信息&…

谷歌的 Astra 是其首款人工智能代理

谷歌将于今年晚些时候推出一款名为 Astra 的新系统,并承诺它将成为迄今为止推出的最强大、最先进的人工智能助手。 当前一代的人工智能助手,例如 ChatGPT,可以检索信息并提供答案,但仅此而已。但今年,谷歌将其助手重…

力扣HOT100 - 322. 零钱兑换

解题思路&#xff1a; 动态规划 class Solution {public int coinChange(int[] coins, int amount) {int[] dp new int[amount 1];Arrays.fill(dp, amount 1);dp[0] 0;for (int i 1; i < amount; i) {for (int j 0; j < coins.length; j) {if (coins[j] < i) …

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

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

Linux 生态与工具

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

简单的DbUtils工具类【精细】

目录 单条通用增删改方法 1.创建maven项目&#xff0c;并加载依赖 2.创建数据库连接工具类(Dbutils类) 3.创建一个执行器(SqlExecutor类) 4.通用(增&#xff0c;删&#xff0c;改)方法 1.创建方法 2.创建userInfo实体类 3.创建测试类&#xff0c;测试增&#xff0c;删&#xf…

k8s的整体架构及其内部工作原理,以及创建一个pod的原理

一、k8s整体架构 二、k8s的作用&#xff0c;为什么要用k8s&#xff0c;以及服务器的发展历程 1、服务器&#xff1a;缺点容易浪费资源&#xff0c;且每个服务器都要装系统&#xff0c;且扩展迁移成本高 2、虚拟机很好地解决了服务器浪费资源的缺点&#xff0c;且部署快&#x…

量化研究---A股赚钱日历,上证指数为例,提供源代码

今天把A股的全部数据导出做了一些赚钱日历分析&#xff0c;看那个月赚钱容易&#xff0c;那个月赚钱困难 导入需要的库 import pandas as pdimport matplotlib.pyplot as pltimport quantstats as qsfrom trader_tool.index_data import index_datafrom trader_tool import j…

IT行业的革新力量:技术进步与未来展望

在当今时代&#xff0c;信息技术&#xff08;IT&#xff09;行业无疑是全球经济的重要推动力之一。随着数字化转型的不断深入&#xff0c;IT行业的边界正在扩大&#xff0c;它不仅包括传统的软硬件开发、网络建设和运维服务&#xff0c;还涵盖了云计算、大数据、人工智能&#…

Http常见问题

这里写自定义目录标题 1. 常见状态码2. HTTP3. HTTP2 1. 常见状态码 2 xxx&#xff1a;成功 4 xxx&#xff1a;一一般是前端错误 5 xxx&#xff1a;一般是后端错误 2. HTTP 记住二点&#xff1a; 无连接&#xff1a;每次连接只处理一个请求&#xff0c;服务器处理完客户的…

LeetCode 126题:单词接龙 II

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

系统思考—团队学习

结束昨日435期JSTO“探索学习的新视界&#xff1a;硬核工具分享”&#xff0c;有伙伴分享的提升效率的AI工具&#xff0c;也有自我发现团队问题解决的工具&#xff0c;伙伴们都在各自的领域实践、吸收、反馈、复盘。这次的团队学习不仅是知识的传递&#xff0c;更是一场脑力激荡…

详解pytorch中循环神经网络(RNN、LSTM、GRU)的维度

详解pytorch中循环神经网络&#xff08;RNN、LSTM、GRU&#xff09;的维度 RNNtorch.nn.rnn详解RNN输入输出维度 LSTMtorch.nn.LSTM详解LSTM输入输出维度 GRUtorch.nn.GRU详解GRU输入输出维度 三种RNN的示例 首先如果你对RNN、LSTM、GRU不太熟悉&#xff0c;可点击查看。 RNN …

2万字实操入门案例之在Springboot框架下用Mybatis简化JDBC开发实现基础的操作MySQL之预编译SQL主键返回增删改查

环境准备 准备数据库表 use mybatis;-- 部门管理 create table dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not null unique comment 部门名称,create_time datetime not null comment 创建时间,update_time datetime not null comme…

做一个犬榜小程序,警示社会。

2024-5-15新闻&#xff1a;流浪狗咬死3岁男童。 相关链接&#xff1a;3岁男童被恶犬咬伤离世 母亲发声 急寻狗主讨公道_中华网 恶狗的主人终于付出代价 链接&#xff1a;这回&#xff0c;恶狗的主人终于付出代价 - 知乎 7岁女童家门口玩耍被恶犬咬伤头面部&#xff0c;多处撕…

【SQL每日一练】获取PADS公司用户名称和各职业总数并根据格式输出

文章目录 题目一、解析二、题解1.MySQL 题目 生成以下两个结果集&#xff1a; 1、查询 OCCUPATIONS 表中所有名字&#xff0c;紧跟每个职业的第一个字母作为括号&#xff08;即&#xff1a;括在括号中&#xff09;&#xff0c;并按名字顺序排序。例如&#xff1a;AnActorName…

OpenCV-android-sdk配置及使用(NDK)

opencv官网下载Android版Releases - OpenCV 下载好OpenCV-android-sdk并解压好,然后新建一个jni文件夹测试,测试项目目录结构如下: ├── jni │ ├── Android.mk │ ├── Application.mk │ └── test.cpp Application.mk: APP_STL := c++_static APP_CPP…

Cow Exhibition G的来龙去脉

[USACO03FALL] Cow Exhibition G - 洛谷 曲折经过 爆搜 一开始没什么好的想法&#xff0c;就针对每头奶牛去or不去进行了爆搜。 #include <cstdio> #include <algorithm> using namespace std;#define maxn 405 int iq[maxn], eq[maxn]; int ans; int n;void d…

Stm32串口搭配DMA实现自定义printf、scanf

前言:本文仅供学习参考使用&#xff0c;主要目的是让大家快速使用串口调试&#xff0c;文章所提及的GCC适用于Clion&#xff0c;Vscode等第三方编辑器的用户。作者有时间会继续更新^_^ 一、GCC环境 1、标准库 (1)、使用方法 在主函数while(1)初始化中&#xff0c;添加Seria…