为什么ChatGPT采用SSE协议而不是Websocket?

在探索ChatGPT的使用过程中,我们发现GPT采用了流式数据返回的方式。理论上,这种情况可以通过全双工通信协议实现持久化连接,或者依赖于基于EventStream的事件流。然而,ChatGPT选择了后者,也就是本文即将深入探讨的SSE(Server-Sent Events)技术。
要理解这个选择,我们需要关注ChatGPT的使用场景。作为一个基于深度学习的大型语言模型,ChatGPT需要处理大量的自然语言数据,这无疑需要大量的计算资源和时间。相较于普通的读取数据库操作,其响应速度自然会慢许多。
对于这种可能需要长时间等待响应的对话场景,ChatGPT采用了一种巧妙的策略:它会将已经计算出的数据“推送”给用户,并利用SSE技术在计算过程中持续返回数据。这样做可以避免用户因等待时间过长而选择关闭页面。
什么是 SSE?
SSE(Server-Sent Events)是一种Web技术,它允许服务器实时向客户端推送数据。相比于传统的轮询和长轮询机制,SSE提供了一种更高效且实时的数据推送方式。这种技术主要应用于构建实时应用,例如实时消息推送、股票行情更新等。
SSE是HTML5规范中的一个通信相关API,它主要包含两个部分:服务端与浏览器端的通信协议(基于HTTP协议),以及浏览器端JavaScript可使用的EventSource对象。
SSE运行在HTTP协议之上,它允许服务器以事件流(Event Stream)的形式将数据发送给客户端。客户端通过建立持久化的HTTP连接,并监听这个事件流,从而可以实时接收到服务器推送的数据。
SSE具有以下几个主要特点:
- 简单易用:SSE使用基于文本的数据格式,如纯文本、JSON等,这使得数据发送和解析都相对简单直接。
- 单向通信:SSE仅支持从服务器到客户端的单向通信。这意味着服务器可以主动推送数据给客户端,但客户端只能被动接收数据。
- 实时性:由于SSE能够建立持久化连接,服务器因此可以实时地将数据推送给客户端,无需客户端频繁地发起请求。这大大提高了数据传输的效率和实时性。
SSE与WebSocket的比较
WebSocket是一种Web技术,用于实现实时双向通信,它与SSE(Server-Sent Events)在某些方面存在差异。以下是对两者的比较:
- 数据推送方向:SSE主要支持从服务器到客户端的单向通信,这意味着服务器可以主动地向客户端推送数据。而WebSocket则支持双向通信,允许服务器和客户端之间进行实时的数据交换。
- 连接建立:SSE利用基于HTTP的长连接,通过常规的HTTP请求和响应来建立连接,进而实现数据的实时推送。相反,WebSocket采用自定义的协议,通过创建WebSocket连接来实现双向通信。
- 兼容性:由于SSE基于HTTP协议,因此它可以在大多数现代浏览器中使用,并且无需进行额外的协议升级。虽然WebSocket在绝大多数现代浏览器中也得到了支持,但在某些特定的网络环境下可能会遇到问题。
- 适用场景:SSE适合于需要服务器向客户端实时推送数据的场景,例如股票价格更新、新闻实时推送等。而WebSocket则适合于需要实时双向通信的场景,如聊天应用、多人在线协作编辑等。
选择使用SSE还是WebSocket主要取决于具体的业务需求和场景。如果你只需要实现从服务器向客户端的单向数据推送,并且希望保持操作简便且兼容性好,那么SSE是一个理想的选择。然而,如果你需要实现双向通信,或者需要更高级的功能和控制,那么WebSocket可能会更适合你的需求。
SSE的实现原理
以下是SSE(Server-Sent Events)的实现原理:
- 连接建立:通常情况下,客户端(如浏览器)通过发送HTTP GET请求到服务器来请求建立一个SSE连接。
- 服务器响应:一旦服务器接收到请求,它将返回一个HTTP响应,该响应的状态码为200,内容类型(Content-Type)设置为"text/event-stream"。
- 数据推送:服务器可以通过已经建立的连接向客户端推送数据。每次推送的数据被称作一个事件(Event)。每个事件由一个或多个以"\n\n"分隔的数据块组成。每个数据块都是一行文本,可能包含一个以":"开头的注释行、以"data:"开头的数据行,或者以"id:"和"event:"开头的行来指定事件ID和事件类型。
- 客户端处理:当客户端接收到服务器推送的事件后,它会触发相应的JavaScript事件处理器来处理这些事件。
- 重连:如果连接断开,客户端会自动尝试重新连接。如果服务器在事件中指定了ID,那么在重新连接时,客户端会发送一个"Last-Event-ID"的HTTP头部信息到服务器,告诉服务器客户端接收到的最后一个事件的ID。根据这个信息,服务器可以决定从哪个事件开始重新发送数据。
总结起来,SSE使用了基于文本和HTTP协议的简单机制,使得服务器能够实时地将数据推送到客户端,而无需客户端频繁地发起新的请求。
使用SSE的注意事项
以下是在使用SSE(Server-Sent Events)技术进行实时数据推送时需要注意的几个关键点:
- 异步处理:由于SSE基于长连接的机制,因此数据推送过程可能会持续较长时间。为了防止服务器线程被阻塞,建议采用异步方式处理SSE请求。例如,可以在控制器方法中使用@Async注解或利用CompletableFuture等异步编程方式。
- 超时处理:SSE连接可能会因网络中断、客户端关闭等原因而超时。为了避免无效连接占据服务器资源,建议设置超时时间并处理超时情况。例如,可以利用SseEmitter对象的setTimeout()方法设定超时时间,并通过onTimeout()方法处理超时逻辑。
- 异常处理:在实际应用中,可能会遇到网络异常、数据推送失败等问题。这种情况下,可以使用SseEmitter对象的completeWithError()方法将异常信息发送给客户端,并在客户端通过eventSource.onerror事件进行处理。
- 内存管理:在使用SseEmitter时,需要特别注意内存管理问题,尤其是在大量并发连接的场景下。当客户端断开连接后,务必及时释放SseEmitter对象,以避免资源泄漏和内存溢出。
- 并发性能:SSE的并发连接数可能对服务器性能产生影响。如果需要处理大量并发连接,可以考虑使用线程池或其他异步处理方式,以最大化服务器资源利用。
- 客户端兼容性:虽然大多数现代浏览器都支持SSE,但一些旧版本的浏览器可能不支持。因此,在使用SSE时,需要确保目标客户端对其有良好的支持,或者提供备选的实时数据推送机制。
以上这些注意事项可以根据具体应用需求进行调整和优化。在实际应用中,确保服务器的稳定性、安全性和性能是非常重要的。同时,在处理SSE连接时,可以考虑适当的限流和安全控制措施,以防止滥用和恶意连接的出现。总的来说,使用SSE技术时需要全面考虑各个方面的因素,才能实现高效、稳定、安全的实时数据推送服务。
SpringBoot集成SSE案例
假设正在开发一个实时股票价格监控应用,需要将股票价格实时推送给客户端。以下为Spring Boot中集成SSE技术实现的场景示例代码。
首先,定义一个控制器来处理SSE请求和发送实时股票价格:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Random;@RestController
public class StockController {@GetMapping(value = "/stock-price", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter streamStockPrice() {SseEmitter emitter = new SseEmitter();// 模拟生成实时股票价格并推送给客户端Random random = new Random();new Thread(() -> {try {while (true) {// 生成随机的股票价格double price = 100 + random.nextDouble() * 10;// 构造股票价格的消息String message = String.format("%.2f", price);// 发送消息给客户端emitter.send(SseEmitter.event().data(message));// 休眠1秒钟Thread.sleep(1000);}} catch (Exception e) {emitter.completeWithError(e);}}).start();return emitter;}
}
在上述代码中,定义了一个streamStockPrice()方法,该方法使用@GetMapping注解将/stock-price路径映射到该方法上,并指定produces = MediaType.TEXT_EVENT_STREAM_VALUE以表明该方法将产生SSE事件流。
在方法内部创建了一个SseEmitter对象作为事件发射器,并在一个单独的线程中不断生成随机的股票价格,并将价格转换为字符串形式发送给客户端。
通过emitter.send()方法发送的数据会被封装为SSE事件流的形式,客户端可以通过监听该事件流来实时接收股票价格。
在前端页面中,创建一个简单的HTML页面来展示实时股票价格:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>实时股票价格监控</title></head><body><h1>实时股票价格</h1><div id="stock-price"></div><script>const eventSource = new EventSource('/stock-price');eventSource.onmessage = function (event) {document.getElementById('stock-price').innerHTML = event.data;};</script></body>
</html>
上述代码中,通过new EventSource('/stock-price')创建了一个EventSource对象,它与/stock-price路径建立SSE连接。然后,通过eventSource.onmessage定义了接收消息的回调函数,在收到新消息时更新页面上的股票价格。
通过以上代码,可以在浏览器中打开该HTML页面,它会建立与服务器的SSE连接,并实时接收并展示股票价格。这只是使用SSE实现实时数据推送的一个简单示例。在实践中,可以根据具体的业务需求和场景,进行更复杂和丰富的实现。
小结
SSE(Server-Sent Events)是一种基于HTTP协议的轻量级实时通信技术,具备服务端推送、断线重连和简单轻量等优点。然而,它也存在一些限制,例如无法进行双向通信、连接数受限以及仅支持GET请求等。
在Web应用程序中,SSE可以实现各种即时数据推送功能,如股票在线数据更新、日志推送、实时显示聊天室人数等。
然而,需要注意的是,并非所有的实时推送场景都适合使用SSE。在需要处理高并发、高吞吐量和低延迟的场景下,WebSocket可能是更好的选择。而对于那些需要轻量级推送解决方案的场景,SSE可能会更加适合。
因此,在选择实时更新方案时,我们需要根据具体的需求和应用场景来做出决策。只有这样,我们才能确保选择的技术能够最大程度地满足我们的需求。
相关文章:
为什么ChatGPT采用SSE协议而不是Websocket?
在探索ChatGPT的使用过程中,我们发现GPT采用了流式数据返回的方式。理论上,这种情况可以通过全双工通信协议实现持久化连接,或者依赖于基于EventStream的事件流。然而,ChatGPT选择了后者,也就是本文即将深入探讨的SSE&…...
Elasticsearch:使用 ELSER v2 文本扩展进行语义搜索
Elastic 提供了一个强大的 ELSER 供我们进行语义搜索。ELSER 是一种稀疏向量的搜索方法。我们无需对它做任何的微调及训练。它是一种 out-of-domain 的模型。目前它仅对英文进行支持。希望将来它能对其它的语言支持的更好。更多关于 ELSER 的知识,请参阅文章 “Elas…...
Matlab:BP神经网络算法,二叉决策树
1、BP神经网络算法 (1)步骤 1.准备训练数据和目标值 2.创建并配置BP神经网络模型 3.训练BP神经网络模型 4.用BP神经网络模型预测数据 例:某企业第一年度营业额为132468,第二年度为158948,第三年度为183737,预测第四年度的营…...
Python实现员工管理系统(Django页面版 ) 七
各位小伙伴们好久不见,2024年即将到来,小编在这里提前祝大家新的一年快快乐乐,能够事业有成,学习顺心,家庭和睦,事事顺利。 今天我们本篇要实现的是一个登录界面的实现,其实登录界面的实现看着挺…...
听GPT 讲Rust源代码--src/tools(34)
File: rust/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs 文件"collection_is_never_read.rs"位于Rust源代码中的clippy_lints工具中,其作用是检查在集合类型(如Vec、HashMap等)的实例上执行的操作是否被忽略了…...
k8s的陈述式资源管理(命令行操作)
(一)k8s的陈述式资源管理 1、命令行:kubectl命令行工具——用于一般的资源管理 (1)优点:90%以上ce场景都可以满足 (2)特点:对资源的增、删、查比较方便,对…...
uniapp uview裁剪组件源码修改(u-avatar-cropper),裁出可自定义固定大小图片
u-avatar-cropper修改后 <template><view class"index"><!-- {{userinfo}} --><view class"top"><view class"bg"><image src"../../static/electronic_card/bg.png"></image></view&g…...
【机器学习前置知识】Beta分布
Beta分布与二项分布的关系 Beta分布与二项分布密切相关,由二项分布扩展而来,它是用来描述一个连续型随机变量出现的概率的概率密度分布,表示为 X X X~ B e t a ( a , b ) Beta(a,b) Beta(a,b) , a 、 b a、b a、b 是形状参数。Beta分布本质上也是一个概率密度函数,只是这…...
Notepad++批量更改文件编码格式及文档格式
背景: 在项目中遇到Windows平台VS的MSVC编译不识别Unix下UTF-8编码导致的编译失败问题。需要将Unix下的UTF-8转为UTF-8-BOM格式。网上找了些方式,之后又深入探究了下文档转换的可能性,共享给大家。(当然Windows和Unix平台代码格式…...
Linux驱动开发学习笔记6《蜂鸣器实验》
目录 一、蜂鸣器驱动原理 二、硬件原理分析 三、实验程序编写 1、 修改设备树文件 (1)添加pinctrl节点 (2)添加BEEP设备节点 (3)检查PIN 是否被其他外设使用 2、蜂鸣器驱动程序编写 3、编写测试AP…...
鸿蒙(HarmonyOS 3.1) DevEco Studio 3.1开发环境汉化
鸿蒙(HarmonyOS 3.1) DevEco Studio 3.1开发环境汉化 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、设置过程 打开IDE,在第一个菜单File 中找到Settings...菜单 在Setting...中找到Plugins…...
毫米波雷达:从 3D 走向 4D
1 毫米波雷达已广泛应用于汽车 ADAS 系统 汽车智能驾驶需要感知层、决策层、执行层三大核心系统的高效配合,其中感知层通过传感器探知周围的环境。汽车智能驾驶感知层将真实世界的视觉、物理、事件等信息转变成数字信号,为车辆了解周边环境、制定驾驶操…...
CENTOS docker拉取私服镜像
概述 docker的应用越来越多,安装部署越来越方便,批量自动化的镜像生成和发布都需要docker镜像的拉取。 centos6版本太老,docker的使用过程中问题较多,centos7相对简单容易。 本文档主要介绍centos系统安装docker和拉取docker私…...
【前端面经】即时设计
目录 前言一面git 常见命令跨窗口通信vue 响应式原理发布订阅模式翻转二叉树Promise.all()扁平化数组面试官建议 二面Event Loop 原理Promise 相关css 描边方式requestAnimationReact 18 新特性JSX 相关react 输出两次函数式编程React 批处理机制http请求头有哪些本地存储性能优…...
前端三件套html/css/js的基本认识以及示例程序
简介 本文简要讲解了html,css,js.主要是让大家简要了解网络知识 因为实际开发中很少直接写html&css,所以不必过多纠结,了解一下架构就好 希望深度学习可以参考MDN和w3school HTML 基础 HTML (Hyper Text Markup Language) 不是一门编程语言,而是一种用来告知浏览器如…...
云计算:OpenStack 配置云主机实例的存储挂载并实现外网互通
目录 一、实验 1. 环境 2.配置存储挂载 3.云主机实例连接外部网络(SNAT) 4.外部网络连接云主机实例(DNAT) 二、问题 1.云主机 ping 不通外部网络 2.nova list 查看云主机列表报错 3.nova list 与 virsh list --all有何区…...
python/selenium/jenkins整合
1、新建python项目,专门写selenium代码,建议用pytest框架写。 2、把代码上传到代码库中。 3、环境配置: 3.1 在跑jenkins的机器上配置好python环境,需要python --version能在任何地方运行(配置好系统环境变量&#…...
华为路由器ACL操作SSH接口
ACL的定义 访问控制列表(Access Control Lists,ACL)是应用在路由器接口的指令列表。这些指令列表用来告诉路由器哪些数据包可以收、哪些数据包需要拒绝。至于数据包是被接收还是拒绝,可以由类似于源地址、目的地址、端口号等的特…...
Flutter 三点三:Dart Stream
Stream Stream用于接收异步事件Stream 可以接收多个异步事件Stream.listen()方法返回StreamSubscription 可用于取消事件订阅,取消后,不再接收事件 基本使用 Stream.fromFutures([Future.delayed(Duration(seconds: 1),(){return "事件1";})…...
centos 防火墙 设置 LTS
centos 防火墙 设置 LTS https://blog.csdn.net/m0_58805648/article/details/130671008...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
JavaScript 标签加载
目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...
