OpenAI是如何实现流式传输的?盘点主流轮询的实现方式

轮询是指客户端定期向服务器查询是否有新的数据更新,是一种常见的实现客户端与服务器数据同步的技术。主要有以下几种轮询方式:

  1. 短轮询(Short Polling)

这是最简单的一种轮询方式。客户端通过setInterval或类似的定时器每隔一段时间向服务器发送一次请求,服务器立即返回响应数据(无论数据是否有更新)。这种方式实现简单,但缺点是无论服务器数据是否更新,请求都会被发送,导致服务器压力较大,资源浪费。

javascript 复制代码
function poll() {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', '/data', true);
  xhr.onload = function() {
    if (xhr.status === 200) {
      // 处理响应数据
      handleData(xhr.responseText);
      // 继续轮询
      setTimeout(poll, 5000); // 5秒后继续轮询
    }
  }
  xhr.send();
}

poll(); // 启动轮询

短轮询适用于对实时性要求不太高,数据更新频率较低的场景,比如定期获取天气预报、股票行情等。

  1. 长轮询(Long Polling)

长轮询技术可以减少不必要的请求,降低服务器压力。客户端发送Ajax请求到服务器后,服务器将请求挂起,直到有新的数据更新才返回响应,客户端收到响应后再次发送新的请求。

这种方式的关键是服务器端要保持请求状态,一旦有新数据就触发响应。连接无法一直保持,需要重新建立新连接。

javascript 复制代码
const http = require('http');

const pendingRequests = [];

const server = http.createServer((req, res) => {
  if (req.url === '/subscribe' && req.method === 'GET') {
    // 将响应挂起
    pendingRequests.push(res);

    // 监听客户端断开连接
    req.on('close', () => {
      pendingRequests.splice(pendingRequests.indexOf(res), 1);
    });
  } else {
    res.statusCode = 404;
    res.end('Not found');
  }
});

// 每隔一段时间向所有挂起的响应推送数据
setInterval(() => {
  const message = { time: new Date().toLocaleTimeString() };
  pendingRequests.forEach((res) => {
    res.write(`data: ${JSON.stringify(message)}\n\n`);
  });
}, 5000);

server.listen(3000, () => console.log('Server is running on http://localhost:3000'));

长轮询适用于偶尔的服务器数据实时更新推送,比如网页操作的实时更新、在线客服实时消息等。

  1. WebSocket

WebSocket是一种全双工的通信协议,可以在单个TCP连接上进行全双工通信,实现服务器主动推送数据给客户端,也允许客户端随时向服务器发送数据。

WebSocket连接建立后,会以两条单向通道的形式工作,服务端和客户端可以随时主动发送数据给对方,全程只建立一次TCP连接,无需像HTTP每次发送请求都建立新连接。

javascript 复制代码
const socket = new WebSocket('ws://example.com/data');

socket.onopen = function() {
  console.log('WebSocket连接已建立');
};

socket.onmessage = function(event) {
  handleData(event.data);
};

socket.onerror = function(error) {
  console.error('WebSocket连接发生错误:', error);
};

WebSocket非常适合需要双向通信的实时场景,如即时通讯、协同编辑、游戏、金融实时报价等,可以最大程度节约服务器资源和带宽。

  1. Server-Sent Events(SSE)

SSE(Server-Sent Events,服务器发送事件)是一种基于HTTP的服务器端向客户端推送数据的技术,OpenAI使用SSE实现了流式传输效果。相比传统的轮询方式,它有以下优点:

  • 服务器推送 传统轮询需要客户端定时向服务器发起请求,而SSE是服务器主动向客户端推送数据,减少了客户端不必要的请求,节省了带宽和服务器资源。

  • 单向通信 SSE是单向通信,即只能由服务器向客户端推送数据,无需客户端发起请求。这种单向通信模型更加高效。

  • 实时性 服务器可以实时地将数据推送给客户端,而不需要等待客户端的轮询。这对于需要实时更新数据的应用非常有用,如在线聊天、实时报价等。

  • 自动重连 如果连接断开,浏览器会自动重新连接到服务器,确保数据流的连续性。

  • 简单 SSE使用HTTP协议,易于开发和部署,且兼容大多数现代浏览器。

SSE的应用场景包括:在线聊天、股票行情更新、社交网络更新、用户在线状态更新、服务器监控等需要服务器实时向多个客户端推送数据的场景。

以下是一个简单的Node.js服务器使用SSE推送数据的示例:

javascript 复制代码
const http = require('http');

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const sendEvent = (data) => res.write(`data: ${JSON.stringify(data)}\n\n`);

  sendEvent({ message: 'Hello from Server-Sent Events!' });

  const intervalId = setInterval(() => sendEvent({ time: new Date().toLocaleTimeString() }), 1000);

  req.on('close', () => {
    console.log('Client disconnected');
    clearInterval(intervalId);
  });
});

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

在浏览器中,可以使用EventSource对象订阅服务器推送的事件:

javascript 复制代码
const eventSource = new EventSource('http://localhost:3000');

eventSource.onmessage = (event) => {
  console.log('Received event:', event.data);
};
相关推荐
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch8 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光8 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   8 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   8 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web8 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery