当前位置: 首页 > 编程日记 > 正文

React + Koa 实现服务端渲染(SSR)

⚛️React是目前前端社区最流行的UI库之一,它的基于组件化的开发方式极大地提升了前端开发体验,React通过拆分一个大的应用至一个个小的组件,来使得我们的代码更加的可被重用,以及获得更好的可维护性,等等还有其他很多的优点...

Part II 版本 传送门

通过React, 我们通常会开发一个单页应用(SPA),单页应用在浏览器端会比传统的网页有更好的用户体验,浏览器一般会拿到一个body为空的html,然后加载script指定的js, 当所有js加载完毕后,开始执行js, 最后再渲染到dom中, 在这个过程中,一般用户只能等待,什么都做不了,如果用户在一个高速的网络中,高配置的设备中,以上先要加载所有的js然后再执行的过程可能不是什么大问题,但是有很多情况是我们的网速一般,设备也可能不是最好的,在这种情况下的单页应用可能对用户来说是个很差的用户体验,用户可能还没体验到浏览器端SPA的好处时,就已经离开网站了,这样的话你的网站做的再好也不会有太多的浏览量。

但是我们总不能回到以前的一个页面一个页面的传统开发吧,现代化的UI库都提供了服务端渲染(SSR)的功能,使得我们开发的SPA应用也能完美的运行在服务端,大大加快了首屏渲染的时间,这样的话用户既能更快的看到网页的内容,与此同时,浏览器同时加载需要的js,加载完后把所有的dom事件,及各种交互添加到页面中,最后还是以一个SPA的形式运行,这样的话我们既提升了首屏渲染的时间,又能获得SPA的客户端用户体验,对于SEO也是个必须的功能?。

OK,我们大致了解了SSR的必要性,下面我们就可以在一个React App中来实现服务端渲染的功能,BTW, 既然我们已经处在一个到处是async/await的环境中,这里的服务端我们使用koa2来实现我们的服务端渲染。

初始化一个普通的单页应用SPA

首先我们先不管服务端渲染的东西,我们先创建一个基于React和React-Router的SPA,等我们把一个完整的SPA创建好后,再加入SSR的功能来最大化提升app的性能。

首先进入app入口 App.js:

import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';const Home = () => <div>Home</div>;
const Hello = () => <div>Hello</div>;const App = () => {return (<Router><Route exact path="/" component={Home} /><Route exact path="/hello" component={Hello} /></Router>)
}ReactDOM.render(<App/>, document.getElementById('app'))
复制代码

上面我们为路由//hello创建了2个只是渲染一些文字到页面的组件。但当我们的项目变得越来越大,组件越来越多,最终我们打包出来的js可能会变得很大,甚至变得不可控,所以呢我们第一步需要优化的是代码拆分(code-splitting),幸运的是通过webpack dynamic import 和 react-loadable,我们可以很容易做到这一点。

用React-Loadable来时间代码拆分

使用之前,先安装 react-loadable:

npm install react-loadable
# or
yarn add react-loadable
复制代码

然后在你的 javascript中:

//...
import Loadable from 'react-loadable';
//...const AsyncHello = Loadable({loading: <div>loading...</div>,//把你的Hello组件写到单独的文件中//然后使用webpack的 dynamic importloader: () => import('./Hello'), 
})//然后在你的路由中使用loadable包装过的组件:
<Route exact path="/hello" component={AsyncHello} />
复制代码

很简单吧,我们只需要import react-loadable, 然后传一些option进去就行了,其中的loading选项是当动态加载Hello组件所需的js时,渲染loading组件,给用户一种加载中的感觉,体验也会比什么都不加好。

好了,现在如果我们访问首页的话,只有Home组件依赖的js才会被加载,然后点击某个链接进入hello页面的话,会先渲染loading组件,并同时异步加载hello组件依赖的js,加载完后,替换掉loading来渲染hello组件。通过基于路由拆分代码到不同的代码块,我们的SPA已经有了很大的优化,cheers?。更叼的是react-loadable同样支持SSR,所以你可以在任意地方使用react-loadable,不管是运行在前端还是服务端,要让react-loadable在服务端正常运行的话我们需要做一些额外的配置,本文后面会讲到,先不急?。‍

到这里我们已经创建好一个基本的React SPA,加上代码拆分,我们的app已经有了不错的性能,但是我们还可以更加极致的优化app的性能,下面我们通过增加SSR的功能来进一步提升加载速度,顺便解决一下SPA中的SEO问题?。

加入服务端渲染(SSR)功能

首先我们先搭建一个最简单的koa web服务器:

npm install koa koa-router
复制代码

然后在koa的入口文件app.js中:

const Koa = require('koa');
const Router = require('koa-router');const app = new Koa();
const router = new Router();
router.get('*', async (ctx) => {ctx.body = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>React SSR</title></head><body><div id="app"></div><script type="text/javascript" src="/bundle.js"></script></body></html>`;
});app.use(router.routes());
app.listen(3000, '0.0.0.0');
复制代码

上面*路由代表任意的url进来我们都默认渲染这个html,包括html中打包出来的js,你也可以用一些服务端模板引擎(如:nunjucks)来直接渲染html文件,在webpack打包时通过html-webpack-plugin来自动插入打包出来的js/css资源路径。

OK, 我们的简易koa server好了,接下来我们开始编写React SSR的入口文件AppSSR.js,这里我们需要使用StaticRouter来代替之前的BrowserRouter,因为在服务端,路由是静态的,用BrowserRouter的话是不起作用的,后面还会做一些配置来使得react-loadable运行在服务端。

提示: 你可以把整个node端的代码用ES6/JSX风格编写,而不是部分commonjs,部分JSX, 但这样的话你需要用webpack把整个服务端的代码编译成commonjs风格,才能使得它运行在node环境中,这里的话我们把React SSR的代码单独抽出去,然后在普通的node代码里去require它。因为可能在一个现有的项目中,之前都是commonjs的风格,把以前的node代码一次性转成ES6的话成本有点大,但是可以后期一步步的再迁移过去

OK, 现在在你的 AppSSR.js中:

import React from 'react';
//使用静态 static router
import { StaticRouter } from 'react-router-dom';
import ReactDOMServer from 'react-dom/server';
import Loadable from 'react-loadable';
//下面这个是需要让react-loadable在服务端可运行需要的,下面会讲到
import { getBundles } from 'react-loadable/webpack';
import stats from '../build/react-loadable.json';//这里吧react-router的路由设置抽出去,使得在浏览器跟服务端可以共用
//下面也会讲到...
import AppRoutes from 'src/AppRoutes';//这里我们创建一个简单的class,暴露一些方法出去,然后在koa路由里去调用来实现服务端渲染
class SSR {//koa 路由里会调用这个方法render(url, data) {let modules = [];const context = {};const html = ReactDOMServer.renderToString(<Loadable.Capture report={moduleName => modules.push(moduleName)}><StaticRouter location={url} context={context}><AppRoutes initialData={data} /></StaticRouter></Loadable.Capture>);//获取服务端已经渲染好的组件数组let bundles = getBundles(stats, modules);return {html,scripts: this.generateBundleScripts(bundles),};}//把SSR过的组件都转成script标签扔到html里generateBundleScripts(bundles) {return bundles.filter(bundle => bundle.file.endsWith('.js')).map(bundle => {return `<script type="text/javascript" src="${bundle.file}"></script>\n`;});}static preloadAll() {return Loadable.preloadAll();}
}export default SSR;
复制代码

当编译这个文件的时候,在webpack配置里使用target: "node"externals,并且在你的打包前端app的webpack配置中,需要加入react-loadable的插件,app的打包需要在ssr打包之前运行,不然拿不到react-loadable需要的各组件信息,先来看app的打包:

//webpack.config.dev.js, app bundle
const ReactLoadablePlugin = require('react-loadable/webpack').ReactLoadablePlugin;module.exports = {//...plugins: [//...new ReactLoadablePlugin({ filename: './build/react-loadable.json', }),]
}
复制代码

.babelrc中加入loadable plugin:

{"plugins": ["syntax-dynamic-import","react-loadable/babel",["import-inspector", {"serverSideRequirePath": true}]]
}
复制代码

上面的配置会让react-loadable知道哪些组件最终在服务端被渲染了,然后直接插入到html script标签中,并在前端初始化时把SSR过的组件考虑在内,避免重复加载,下面是SSR的打包:

//webpack.ssr.js
const nodeExternals = require('webpack-node-externals');module.exports = {//...target: 'node',output: {path: 'build/node',filename: 'ssr.js',libraryExport: 'default',libraryTarget: 'commonjs2',},//避免把node_modules里的库都打包进去,此ssr js会直接运行在node端,//所以不需要打包进最终的文件中,运行时会自动从node_modules里加载externals: [nodeExternals()],//...
}
复制代码

然后在koa app.js, require它,并且调用SSR的方法:

//...koa app.js
//build出来的ssr.js
const SSR = require('./build/node/ssr');
//preload all components on server side, 服务端没有动态加载各个组件,提前先加载好
SSR.preloadAll();//实例化一个SSR对象
const s = new SSR();router.get('*', async (ctx) => {//根据路由,渲染不同的页面组件const rendered = s.render(ctx.url);const html = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"></head><body><div id="app">${rendered.html}</div><script type="text/javascript" src="/runtime.js"></script>${rendered.scripts.join()}<script type="text/javascript" src="/app.js"></script></body></html>`;ctx.body = html;
});
//...
复制代码

以上是个简单的实现React SSR到koa web server, 为了使react-loadable知道哪些组件在服务端渲染了,rendered里面的scripts数组里面包含了SSR过的组件组成的各个script标签,里面调用了SSR#generateBundleScripts()方法,在插入时需要确保这些script标签在runtime.js之后((通过 CommonsChunkPlugin 来抽出来)),并且在app bundle之前(也就是初始化的时候应该已经知道之前的哪些组件已经渲染过了)。更多react-loadable服务端支持,参考这里.

上面我们还把react-router的路由都单独抽出去了,使得它可以运行在浏览器跟服务端,以下是AppRoutes组件:

//AppRoutes.js
import Loadable from 'react-loadable';
//...const AsyncHello = Loadable({loading: <div>loading...</div>,loader: () => import('./Hello'), 
})function AppRoutes(props) {<Switch><Route exact path="/hello" component={AsyncHello} /><Route path="/" component={Home} /></Switch>  
}export default AppRoutes//然后在 App.js 入口中
import AppRoutes from './AppRoutes';
// ...
export default () => {return (<Router><AppRoutes/></Router>)
}
复制代码

服务端渲染的初始状态

目前为止,我们已经创建了一个React SPA,并且能在浏览器端跟服务端共同运行?,社区称之为universal app 或者 isomophic app。但是我们现在的app还有一个遗留问题,一般来说我们app的数据或者状态都需要通过远端的api来异步获取,拿到数据后我们才能开始渲染组件,服务端SSR也是一样,我们要动态的获取初始数据,然后才能扔给React去做SSR,然后在浏览器端我们还要初始化就能同步获取这些SSR时的初始化数据,避免浏览器端初始化时又重新获取了一遍。

下面我们简单从github获取一些项目的信息作为页面初始化的数据, 在koa的app.js中:

//...
const fetch = require('isomorphic-fetch');router.get('*', async (ctx) => {//fetch branch info from githubconst api = 'https://api.github.com/repos/jasonboy/wechat-jssdk/branches';const data = await fetch(api).then(res => res.json());//传入初始化数据const rendered = s.render(ctx.url, data);const html = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"></head><body><div id="app">${rendered.html}</div><script type="text/javascript">window.__INITIAL_DATA__ = ${JSON.stringify(data)}</script><script type="text/javascript" src="/runtime.js"></script>${rendered.scripts.join()}<script type="text/javascript" src="/app.js"></script></body></html>`;ctx.body = html;
});
复制代码

然后在你的Hello组件中,你需要checkwindow里面(或者在App入口中统一判断,然后通过props传到子组件中)是否存在window.__INITIAL_DATA__,有的话直接用来当做初始数据,没有的话我们在componentDidMount生命周期函数中再去来数据:

export default class Hello extends React.Component {constructor(props) {super(props);this.state = {//这里直接判断window,如果是父组件传入的话,通过props判断github: window.__INITIAL_DATA__ || [],};}componentDidMount() {//判断没有数据的话,再去请求数据//请求数据的方法也可以抽出去,以让浏览器及服务端能统一调用,避免重复写if (this.state.github.length <= 0) {fetch('https://api.github.com/repos/jasonboy/wechat-jssdk/branches').then(res => res.json()).then(data => {this.setState({ github: data });});}}render() {return (<div><ul>{this.state.github.map(b => {return <li key={b.name}>{b.name}</li>;})}</ul></div>);}
}
复制代码

好了,现在如果页面被服务端渲染过的话,浏览器会拿到所有渲染过的html, 包括初始化数据,然后通过这些SSR的内容配合加载的js,再组成一个完整的SPA,就像一个普通的SPA一样,但是我们得到了更好的性能,更好的SEO?。

?React-v16 更新

在React的最新版v16中,SSR的API做了很多的优化,并且提供了新的基于流的API来更好的提升性能,通过streaming api, 服务端可以边渲染边把前面渲染好的html发到浏览器,浏览器端也可以提前开始渲染页面而不是等服务端所有组件都渲染完成后才能开始浏览器端的初始化,提升了性能也降低了服务端资源的消耗。还有一个在浏览器端需要注意的是需要使用ReactDOM.hydrate()来代替之前的ReactDOM.render(),更多的更新参考medium文章whats-new-with-server-side-rendering-in-react-16.

?要查看完整的demo, 参考 koa-web-kit, koa-web-kit是一个现代化的基于React/Koa的全栈开发框架,包括React SSR支持,可以直接用来测试服务端渲染的功能?

结论

好了,以上就是React-SSR + Koa的简单实践,通过SSR,我们既提升了性能,又很好的满足了SEO的要求,Best of the Both Worlds?。

PPT in Browser

English Version

相关文章:

11 款可替代 top 命令的工具!

‍‍作者 | JackTian来源 | 杰哥的IT之旅在 Linux 环境下 top 命令都不陌生&#xff0c;它以实时动态的方式查看系统的整体运行情况&#xff0c;综合了多方信息监测系统性能和运行信息的实用工具&#xff0c;通过 top 命令所提供的互动式界面&#xff0c;可以用热键来进行管理。…

几个重要的RFC

RFC目录 权威无须解释 http://www.ietf.org/rfc/RFC中文目录http://man.chinaunix.net/develop/rfc/default.htm几个常用的RFC参考&#xff1a; RFC1945 超文本传输协议--HTTP/1.0 RFC2616超文本传输协议--HTTP/1.1 对 RFC2068的补充RFC3920可扩展的消息和出席信息协议 (XMPP)…

iOS开发笔记-两种单例模式的写法

iOS开发笔记&#xff0d;两种单例模式的写法 单例模式是开发中最常用的写法之一&#xff0c;iOS的单例模式有两种官方写法&#xff0c;如下&#xff1a; 不使用GCD #import "ServiceManager.h"static ServiceManager *defaultManager;implementation ServiceManager(…

流式大数据处理的三种框架:Storm,Spark和Samza

2019独角兽企业重金招聘Python工程师标准>>> 许多分布式计算系统都可以实时或接近实时地处理大数据流。本文将对三种Apache框架分别进行简单介绍&#xff0c;然后尝试快速、高度概述其异同。 Apache Storm 在Storm中&#xff0c;先要设计一个用于实时计算的图状结构…

CentOS用yum安装X Window

安装X图形界面系统yum list 列出所有可安装的软件包 可以通过 yum grouplist 来查看可能批量安装哪些列表 先装X windows #yum groupinstall X Window System -y 安装GNOME桌面环境#yum groupinstall GNOME Desktop Environment -y 安装KDE桌面环境#yum groupinstall KDE (K D…

Oracle VDI 安装

为什么80%的码农都做不了架构师&#xff1f;>>> 你可以在这里找到本文的原文。 虽然说Oracle已经停止了VDI的开发&#xff0c;之后支持服务业很快停止了。但是&#xff0c;作为经典的桌面虚拟化产品&#xff0c;还是值得研究一番。虽然Oracle VDI的文档已经写的很详…

Python 写了一个网页版的「P图软件」,惊呆了!

作者 | 小欣来源 | Python爱好者集中营今天是开工第一天&#xff0c;这篇文章可以算作是虎年的第一篇干货技术类文章了&#xff0c;今天小编用Python做了一个网页版的“P图软件”&#xff0c;大致的流程在于我们可以将上传的照片进行黑白处理、铅笔素描处理、模糊化处理等一系列…

Template mode HTML5 has not been configured

#thymeleafspring.thymeleaf.prefixclasspath:/templates/spring.thymeleaf.suffix.htmlspring.thymeleaf.cachefalsespring.thymeleaf.content-typetext/htmlspring.thymeleaf.enabledtruespring.thymeleaf.encodingUTF-8spring.thymeleaf.modeHTML5 解决办法&#xff1a;注释…

Java数据结构与算法(第四章栈和队列)

2019独角兽企业重金招聘Python工程师标准>>> 本章涉及的三种数据存储类型&#xff1a;栈、队列和优先级队列。 不同类型的结构 程序员的工具 数组是已经介绍过的数据存储结构&#xff0c;和其他结构&#xff08;链表、树等等&#xff09;一样&#xff0c;都适用于数…

可构建AI的「AI」诞生:几分之一秒内,就能预测新网络的参数

‍‍来源 | 学术头条人工智能在很大程度上是一场数字游戏。当深度神经网络在 10 年前开始超越传统算法&#xff0c;是因为我们终于有了足够的数据和处理能力来充分利用它们。今天的神经网络更依赖于数据和算力。训练网络时&#xff0c;需要仔细调整表征网络的数百万甚至数十亿参…

It is not safe to rely on the system's timezone settings

在写php程序中有时会出现这样的警告&#xff1a; PHP Warning: date(): It is not safe to rely on the systems timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those metho…

.NET MVC+ EF+LINQ 多表联查VIEW显示列表

1.VIEW 页面显示代码 <link href"~/Content/bootstrap.css" rel"stylesheet" /><div class"well"><table class"table"><tr><th>用户名</th><th>地址</th><th>订单编号</th…

从奥运订票系统说起——谈FastCGI 与IT 架构

2008年&#xff0c;对于首都人民来说&#xff0c;没有什么比奥运会更大的事情了。如何买到一张称心如意的比赛门票&#xff0c;也成了很多人的一个梦想。然而&#xff0c;在奥运官网抢票购买的时候&#xff0c;这个梦想却轻易地被网上购票系统的当机击成碎片&#xff0c;很多充…

【哲学百科】文艺复兴及唯理主义时期(公元1500~公元1750)

我为达目的&#xff0c;不择手段-尼古拉.马基雅维利要令习惯于君主统治的民众保有自由是一件多么困难的事情。马基雅维利的观点之一是君主不应受到道德标准的束缚&#xff0c;而应竭尽所能保全自身的荣耀以及所统治的城邦的胜利与繁荣&#xff0c;这种做法随后被人们归为现实主…

如何用 OpenGL 绘制雪花?

作者 | 许向武 责编 | 张红月出品 | CSDN博客看冬奥才知道&#xff0c;阿勒泰不但是中国的“雪都”&#xff0c;还是“人类滑雪起源地”。这个说法是否成立&#xff0c;姑且不论&#xff0c;阿勒泰的雪的确很漂亮。冬奥会有一个宣传片&#xff0c;就是借用一朵阿勒泰雪花…

面试之Hashtable和ConcurrentHashMap

那么要如何保证HashMap的线程安全呢&#xff1f; 方法有很多&#xff0c;比如使用Hashtable或者Collections.synchronizedMap&#xff0c;但是这两位选手都有一个共同的问题&#xff1a;性能。因为不管是读还是写操作&#xff0c;他们都会给整个集合上锁&#xff0c;导致同一时…

PHP动态编译出现Cannot find autoconf

在安装完PHP后,想动态编译PHP的memcache扩展库 cd memcache-2.2.5//usr/local/webserver/php/bin/phpize./configure --with-php-config/usr/local/webserver/php/bin/php-config 但是执行/usr/local/webserver/php/bin/phpize时出现错误:Configuring for:PHP Api Version: …

AnimeGANv2 实现动漫风格迁移,简单操作

作者 | Yunlord出品 | CSDN博客前言之前一直在研究如何将图像动漫化&#xff0c;尝试了阿里云api和百度api&#xff0c;效果都不尽如人意。结果发现了一个宝藏github项目——AnimeGANv2&#xff0c;能够将现实世界场景照片进行动漫风格化。可以看出AnimeGAN的效果非常好&#x…

C#调用win32 api程序实例

1、声明static extern 方法&#xff0c;使用DllImport特性 class MyClass{[DllImport("kernel32", SetLastError true)]public static extern int GetCurrentDirectory(int a, StringBuilder b);} 2、调用 StringBuilder sbnew StringBuilder {Length 250}; MyClas…

Python 之 pip拒绝访问

起因 在我使用pip安装第三方库的时候&#xff0c;控制台提示我升级pip版本 You are using pip version 9.0.1, however version 10.0.1 is available. You should consider upgrading via the python -m pip install --upgrade pip command. 很显然&#xff0c;需要使用这样的指…

Unix / 类 Unix shell 中有哪些很酷很冷门很少用很有用的命令?(转)

著作权归作者所有。 商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 作者&#xff1a;孙立伟 链接&#xff1a;http://www.zhihu.com/question/20140085/answer/14107336 来源&#xff1a;知乎 这个问题quora上有人提过 What are some lesser known but useful…

干货满满的 Python 实战项目,点赞收藏

作者 | 俊欣来源 | 关于数据分析与可视化今天小编来给大家介绍3个干货满满的计算机视觉方向的Python实战项目&#xff0c;主要用到的库有opencv-pythonnumpypillow要是大家所配置的环境当中没有这几个模块的话&#xff0c;就需要先用pip命令下载安装pip install opencv-python …

php安装完成以后要复制php.ini文件

直接 #find / -name "php.ini" 找不到&#xff0c;是因为安装php的时候没有复制配置文件 php版本变化以后ini文件名有变 php.ini-production对应于php.ini-recommended php.ini-development对应于php.ini-dist二者差异&#xff1f; 由于版本更新,这些文件有了新的命…

MASQUERADE --random 端口不随机

iptables -t nat -A POSTROUTING -o xxxx -j MASQUERADE --random发现源端口并不是随机的而是有规律递增&#xff0c;经过Google的搜索查找&#xff0c;发现新的版本有--random-full 这个参数iptables -t nat -A POSTROUTING -o xxxx -j MASQUERADE --random-full经过测试端口随…

PHP安装与使用VLD查看opcode代码【PHP安装第三方扩展的方法】

需要分析PHP代码的性能&#xff0c;或者说实现同样功能的代码到底哪个更好呢&#xff1f;或者说想知道底层的实现可以使用VLD查看opcode 下载与安装VLD # wget http://pecl.php.net/get/vld-0.11.2.tgz# tar zxvf vld-0.11.2.tgz# cd ./vld-0.11.2# /usr/local/php/bin/phpize …

实现数组字符串翻转的两种方法

//第一种方法&#xff1a;递归法 #include <stdio.h> int reverse_string(char * string) {if (*string ! \0){reverse_string(string1);printf("%c", *string);} } int main() {char *string "abcde";printf("源字符串为&#xff1a;%s\n&quo…

详解 Python 如何将爬取到的数据分别存储到 txt、excel、mysql 中!

作者 | 黄伟呢来源 | 数据分析与统计学之美1. 页面分析我爬取的页面是腾讯体育&#xff0c;链接如下&#xff1a;https://nba.stats.qq.com/player/list.htm观察上图&#xff1a;左边展示的分别是NBA的30支球队&#xff0c;右边就是每只球队对应球员的详细信息。此时思路就很清…

蹭了BCH热度,还来诋毁BCH,这些跳梁小丑到底在玩什么阴谋?

最近一些分叉币为了博眼球简直什么招数都用。有的某分叉币对主链暂停10天的问题闭口不提&#xff0c;靠微博撕逼来吸引关注&#xff0c;有的则自导自演了一出51%***的大戏。而奇怪的是当别人开始谈论他们这些错误的时候&#xff0c;他们却把矛头指向了火热的比特币现金。这些跳…

比 GPT-3 更擅长理解用户意图,OpenAI发布 InstructGPT

作者 | 青苹果来源 | 数据实战派近日&#xff0c;OpenAI 发布了一项令人瞩目的研究—— InstructGPT。在这项研究中&#xff0c;相比 GPT-3 而言&#xff0c;OpenAI 采用对齐研究&#xff08;alignment research&#xff09;&#xff0c;训练出更真实、更无害&#xff0c;而且更…

The C10K problem原文翻译

原文地址&#xff1a;http://www.cnblogs.com/fll/archive/2008/05/17/1201540.htmlThe C10K problem如今的web服务器需要同时处理一万个以上的客户端了&#xff0c;难道不是吗&#xff1f;毕竟如今的网络是个big place了。 现在的计算机也很强大了&#xff0c;你只需要花大概$…