如何写超强伸缩性的多游戏玩家服务器

附标题:如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身

原文:[url=http://www.devmaster.net/articles/mmo-scalable-server/]Writing Low-Pain Massively Scalable Multiplayer Servers[/url]

[b]介绍[/b]
本文以我的OpenPoker项目为例子,讲述了一个构建超强伸缩性的在线多游戏玩家系统。
OpenPoker是一个超强多玩家纸牌服务器,具有容错、负载均衡和无限伸缩性等特性。
源代码位于我的个人站点上,大概10,000行代码,其中1/3是测试代码。

在OpenPoker最终版本敲定之前我做了大量调研,我尝试了Delphi、Python、C#、C/C++和Scheme。我还用Common Lisp写了纸牌引擎。
虽然我花费了9个月的时间研究原型,但是最终重写时只花了6个星期的时间。
我认为我所节约的大部分时间都得益于选择Erlang作为平台。

相比之下,旧版本的OpenPoker花费了一个4~5人的团队9个月时间。

[b]Erlang是什么东东?[/b]
我建议你在继续阅读本文之前浏览下Erlang FAQ,这里我给你一个简单的总结...

Erlang是一个函数式动态类型编程语言并自带并发支持。它是由Ericsson特别为控制开关、转换协议等电信应用设计的。
Erlang十分适合构建分布式、软实时的并发系统。

由Erlang所写的程序通常由成百上千的轻量级进程组成,这些进程通过消息传递来通讯。
Erlang进程间的上下文切换通常比C程序线程的上下文切换要廉价一到两个数量级。

使用Erlang写分布式程序很简单,因为它的分布式机制是透明的:程序不需要了解它们是否分布。

Erlang运行时环境是一个虚拟机,类似于Java虚拟机。这意味着在一个价格上编译的代码可以在任何地方运行。
运行时系统也允许在一个运行着的系统上不间断的更新代码。
如果你需要额外的性能提升,字节码也可以编译成本地代码。

请移步Erlang site,参考Getting started、Documentation和Exampes章节等资源。

[b]为何选择Erlang?[/b]
构建在Erlang骨子里的并发模型特别适合写在线多玩家服务器。

一个超强伸缩性的多玩家Erlang后端构建为拥有不同“节点”的“集群”,不同节点做不同的任务。
一个Erlang节点是一个Erlang VM实例,你可以在你的桌面、笔记本电脑或服务器上上运行多个Erlang节点/VM。
推荐一个CPU一个节点。

Erlang节点会追踪所有其他和它相连的节点。向集群里添加一个新节点所需要的只是将该新节点指向一个已有的节点。
一旦这两个节点建立连接,集群里所有其他的节点都会知晓这个新节点。

Erlang进程使用一个进程id来相互发消息,进程id包含了节点在哪里运行的信息。进程不需要知道其他进程在哪里就可以通讯。
连接在一起的Erlang节点集可以看作一个网格或者超级计算设备。

超多玩家游戏里玩家、NPC和其他实体最好建模为并行运行的进程,但是并行很难搞是众所皆知的。Erlang让并行变得简单。

Erlang的位语法∞让它在处理结构封装/拆解的能力上比Perl和Python都要强大。这让Erlang特别适合处理二进制网络协议。

[b]OpenPoker架构[/b]
OpenPoker里的任何东西都是进程。玩家、机器人、游戏等等多是进程。
对于每个连接到OpenPoker的客户端都有一个玩家“代理”来处理网络消息。
根据玩家是否登录来决定部分消息忽略,而另一部分消息则发送给处理纸牌游戏逻辑的进程。

纸牌游戏进程是一个状态机,包含了游戏每一阶段的状态。
这可以让我们将纸牌游戏逻辑当作堆积木,只需将状态机构建块放在一起就可以添加新的纸牌游戏。
如果你想了解更多的话可以看看cardgame.erl的start方法。

纸牌游戏状态机根据游戏状态来决定不同的消息是否通过。
同时也使用一个单独的游戏进程来处理所有游戏共有的一些东西,如跟踪玩家、pot和限制等等。
当在我的笔记本电脑上模拟27,000个纸牌游戏时我发现我拥有大约136,000个玩家以及总共接近800,000个进程。

下面我将以OpenPoker为例子,专注于讲述怎样基于Erlang让实现伸缩性、容错和负载均衡变简单。
我的方式不是特别针对纸牌游戏。同样的方式可以用在其他地方。

[b]伸缩性[/b]
我通过多层架构来实现伸缩性和负载均衡。
第一层是网关节点。
游戏服务器节点组成第二层。
Mnesia“master”节点可以认为是第三层。

Mnesia是Erlang实时分布式数据库。Mnesia FAQ有一个很详细的解释。Mnesia基本上是一个快速的、可备份的、位于内存中的数据库。
Erlang里没有对象,但是Mnesia可以认为是面向对象的,因为它可以存储任何Erlang数据。

有两种类型的Mnesia节点:写到硬盘的节点和不写到硬盘的节点。除了这些节点,所有其他的Mnesia节点将数据保存在内存中。
在OpenPoker里Mnesia master节点会将数据写入硬盘。网关和游戏服务器从Mnesia master节点获得数据库并启动,它们只是内存节点。

当启动Mnesia时,你可以给Erlang VM和解释器一些命令行参数来告诉Mnesia master数据库在哪里。
当一个新的本地Mnesia节点与master Mnesia节点建立连接之后,新节点变成master节点集群的一部分。

假设master节点位于apple和orange节点上,添加一个新的网关、游戏服务器等等。OpenPoker集群简单的如下所示:
[code]
erl -mnesia extra_db_nodes \['db@apple','db@orange'\] -s mnesia start
[/code]
-s mnesia start相当于这样在erlang shell里启动Mnedia:
[code]
erl -mnesia extra_db_nodes \['db@apple','db@orange'\]
Erlang (BEAM) emulator version 5.4.8 [source] [hipe] [threads:0]

Eshell V5.4.8 (abort with ^G)
1> mnesia:start().
ok
[/code]
OpenPoker在Mnesia表里保存配置信息,并且这些信息在Mnesia启动后立即自动被新的节点下载。零配置!

[b]容错[/b]
通过添加廉价的Linux机器到我的服务器集群,OpenPoker让我随心所欲的变大。
将几架1U的服务器放在一起,这样你就可以轻易的处理500,000甚至1,000,000的在线玩家。这对MMORPG也是一样。

我让一些机器运行网关节点,另一些运行数据库master来写数据库事务到硬盘,让其他的机器运行游戏服务器。
我限制游戏服务器接受最多5000个并发的玩家,这样当游戏服务器崩溃时最多影响5000个玩家。

值得注意的是,当游戏服务器崩溃时没有任何信息丢失,因为所有的Mnesia数据库事务都是实时备份到其他运行Mnesia以及游戏服务器的节点上的。

为了预防出错,游戏客户端必须提供一些援助来平稳的重连接OpenPoker集群。
一旦客户端发现一个网络错误,它应该连接网关,接受一个新的游戏服务器地址,然后重新连接新的游戏服务器。
下面发生的事情需要一定技巧,因为不同类型的重连接场景需要不同的处理。

OpenPoker会处理如下几种重连接的场景:
1,游戏服务器崩溃
2,客户端崩溃或者由于网络原因超时
3,玩家在线并且在一个不同的连接上
4,玩家在线并且在一个不同的连接上并在一个游戏中

最常见的场景是一个客户端由于网络出错而重新连接。
比较少见但仍然可能的场景是客户端已经在一台机器上玩游戏,而此时从另一台机器上重连接。

每个发送给玩家的OpenPoker游戏缓冲包和每个重连接的客户端将首先接受所有的游戏包,因为游戏不是像通常那样正常启动然后接受包。
OpenPoker使用TCP连接,这样我不需要担心包的顺序——包会按正确的顺序到达。

每个客户端连接由两个OpenPoker进程来表现:socket进程和真正的玩家进程。
先使用一个功能受限的visitor进程,直到玩家登录。例如visitor不能参加游戏。
在客户端断开连接后,socket进程死掉,而玩家进程仍然活着。

当玩家进程尝试发送一个游戏包时可以通知一个死掉的socket,并让它自己进入auto-play模式或者挂起。
在重新连接时登录代码将检查死掉的socket和活着的玩家进程的结合。代码如下:
[code]
login({atomic, [Player]}, [_Nick, Pass|_] = Args)
when is_record(Player, player) ->
Player1 = Player#player {
socket = fix_pid(Player#player.socket),
pid = fix_pid(Player#player.pid)
},
Condition = check_player(Player1, [Pass],
[
fun is_account_disabled/2,
fun is_bad_password/2,
fun is_player_busy/2,
fun is_player_online/2,
fun is_client_down/2,
fun is_offline/2
]),
...
[/code]
condition本身由如下代码决定:
[code]
is_player_busy(Player, _) ->
{Online, _} = is_player_online(Player, []),
Playing = Player#player.game /= none,
{Online and Playing, player_busy}.

is_player_online(Player, _) ->
SocketAlive = Player#player.socket /= none,
PlayerAlive = Player#player.pid /= none,
{SocketAlive and PlayerAlive, player_online}.

is_client_down(Player, _) ->
SocketDown = Player#player.socket == none,
PlayerAlive = Player#player.pid /= none,
{SocketDown and PlayerAlive, client_down}.

is_offline(Player, _) ->
SocketDown = Player#player.socket == none,
PlayerDown = Player#player.pid == none,
{SocketDown and PlayerDown, player_offline}.
[/code]
注意login方法的第一件事是修复死掉的进程id:
[code]
fix_pid(Pid)
when is_pid(Pid) ->
case util:is_process_alive(Pid) of
true ->
Pid;
_->
none
end;

fix_pid(Pid) ->
Pid.
[/code]
以及:
[code]
-module(util).

-export([is_process_alive/1]).

is_process_alive(Pid)
when is_pid(Pid) ->
rpc:call(node(Pid), erlang, is_process_alive, [Pid]).
[/code]
Erlang里一个进程id包括正在运行的进程的节点的id。
is_pid(Pid)告诉我它的参数是否是一个进程id(pid),但是不能告诉我进程是活着还是死了。
Erlang自带的erlang:is_process_alive(Pid)告诉我一个本地进程(运行在同一节点上)是活着还是死了,但没有检查远程节点是或者还是死了的is_process_alive变种。

还好,我可以使用Erlang rpc工具和node(pid)来在远程节点上调用is_process_alive()。
事实上,这跟在本地节点上一样工作,这样上面的代码就可以作为全局分布式进程检查器。

剩下的唯一的事情是在不同的登录条件上活动。
最简单的情况是玩家离线,我期待一个玩家进程,连接玩家到socket并更新player record。
[code]
login(Player, player_offline, [Nick, _, Socket]) ->
{ok, Pid} = player:start(Nick),
OID = gen_server:call(Pid, 'ID'),
gen_server:cast(Pid, {'SOCKET', Socket}),
Player1 = Player#player {
oid = OID,
pid = Pid,
socket = Socket
},
{Player1, {ok, Pid}}.
[/code]
假如玩家登陆信息不匹配,我可以返回一个错误并增加错误登录次数。如果次数超过一个预定义的最大值,我就禁止该帐号:
[code]
login(Player, bad_password, _) ->
N = Player#player.login_errors + 1,
{atomic, MaxLoginErrors} =
db:get(cluster_config, 0, max_login_errors),
if
N > MaxLoginErrors ->
Player1 = Player#player {
disabled = true
},
{Player1, {error, ?ERR_ACCOUNT_DISABLED}};
true ->
Player1 = Player#player {
login_errors =N
},
{Player1, {error, ?ERR_BAD_LOGIN}}
end;

login(Player, account_disabled, _) ->
{Player, {error, ?ERR_ACCOUNT_DISABLED}};
[/code]
注销玩家包括使用Object ID(只是一个数字)找到玩家进程id,停止玩家进程,然后在数据库更新玩家record:
[code]
logout(OID) ->
case db:find(player, OID) of
{atomic, [Player]} ->
player:stop(Player#player.pid),
{atomic, ok} = db:set(player, OID,
[{pid, none},
{socket, none}];
_->
oops
end.
[/code]
这样我就可以完成多种重连接condition,例如从不同的机器重连接,我只需先注销再登录:
[code]
login(Player, player_online, Args) ->
logout(Player#player.oid),
login(Player, player_offline, Args);
[/code]
如果玩家空闲时客户端重连接,我所需要做的只是在玩家record里替换socket进程id然后告诉玩家进程新的socket:
[code]
login(Player, client_down, [_, _, SOcket]) ->
gen_server:cast(Player#player.pid, {'SOCKET', Socket}),
Player1 = Player#player {
socket = Socket
},
{Player1, {ok, Player#player.pid}};
[/code]
如果玩家在游戏中,这是我们运行上面的代码,然后告诉游戏重新发送时间历史:
[code]
login(Player, player_busy, Args) ->
Temp = login(Player, client_down, Args),
cardgame:cast(Player#player.game,
{'RESEND UPDATES', Player#player.pid}),
Temp;
[/code]
总体来说,一个实时备份数据库,一个知道重新建立连接到不同的游戏服务器的客户端和一些有技巧的登录代码运行我提供一个高级容错系统并且对玩家透明。

[b]负载均衡[/b]
我可以构建自己的OpenPoker集群,游戏服务器数量大小随心所欲。
我希望每台游戏服务器分配5000个玩家,然后在集群的活动游戏服务器间分散负载。
我可以在任何时间添加一个新的游戏服务器,并且它们将自动赋予自己接受新玩家的能力。

网关节点分散玩家负载到OpenPoker集群里活动的游戏服务器。
网关节点的工作是选择一个随机的游戏服务器,询问它所连接的玩家数量和它的地址、主机和端口号。
一旦网关找到一个游戏服务器并且连接的玩家数量少于最大值,它将返回该游戏服务器的地址到连接的客户端,然后关闭连接。

网关上绝对没有压力,网关的连接都非常短。你可以使用非常廉价的机器来做网关节点。

节点一般都成双成对出现,这样一个节点崩溃后还有另一个继续工作。你可能需要一个类似于Round-robin DNS的机制来保证不只一个单独的网关节点。

网关怎么知晓游戏服务器?

OpenPoker使用Erlang Distirbuted Named Process Groups工具来为游戏服务器分组。
该组自动对所有的节点全局可见。
新的游戏服务器进入游戏服务器后,当一个游戏服务器节点崩溃时它被自动删除。

这是寻找容量最大为MaxPlayers的游戏服务器的代码:
[code]
find_server(MaxPlayers) ->
case pg2:get_closest_pid(?GAME_SERVER) of
Pid when is_pid(Pid) ->
{Time, {Host, Port}} = timer:tc(gen_server, call, [Pid, 'WHERE']),
Coutn = gen_server:call(Pid, 'USER COUNT'),
if
Count < MaxPlayers ->
io:format("~s:~w ~w players~n", [Host, Port, Count]),
{Host, Port};
true ->
io:format("~s:~w is full...~n", [Host, Port]),
find_server(MaxPlayers)
end;
Any ->
Any
end.
[/code]
pg2:get_closest_pid()返回一个随机的游戏服务器进程id,因为网关节点上不允许跑任何游戏服务器。
如果一个游戏服务器进程id返回,我询问游戏服务器的地址(host和port)和连接的玩家数量。
只要连接的玩家数量少于最大值,我返回游戏服务器地址给调用者,否则继续查找。

[b]多出口电源插座中间件[/b]
OpenPoker是一个开源软件,我最近在将它推销给多个纸牌游戏厂商。
所有的厂商都有同样的伸缩性和容错的问题,即使做了多年开发。
有的最近刚刚完成服务器软件重写,而有的刚刚开始。
所有的厂商都严重依赖于它们的Java基础架构,可以理解,它们不想换Erlang。

看来有一个需求必须满足。我思考的越多,发现Erlang越适合提供高效的解决方案。
我把这个解决方案看作一个多出口电源插座。

你可以像写一个使用数据库后端的基于socket的服务器一样来写游戏服务器。
事实上,目前游戏服务器就是这样写的。
游戏服务器是标准的电源插头,游戏服务器的多个实例插入到电源插座中,而玩家从另一端流过。

你提供游戏服务器,而我提供伸缩性、负载均衡和容错。
我让玩家连接到电源插座并监控你的游戏服务器,必要时重启它们。
当一个游戏服务器崩溃时我将玩家切换到另一台游戏服务器,你可以往插座里插入任意多的游戏服务器。

电源插座中间件是一个黑盒子,它位于你的玩家和你的服务器之间,很可能不需要你改动任何代码。
你会得到伸缩性、负载均衡、容错等诸多益处而只需改动极少的一部分现有架构。

今天你就可以用Erlang写这个中间件,然后运行在一个内核调优过以支持大量TCP连接的Linux机器上,而将你的服务器放在一个防火墙后面。
即使你不这样做,我建议你马上仔细看看Erlang,想想如何使用它来简化你的超强多玩家服务器架构。而我会在这儿帮助你!
Erlang 游戏服务器开发:增强好友系统功能 我们的目标是构建一个可扩展和高效的好友系统,使玩家能够添加、删除和查找好友,并实现在线状态的跟踪。为了实现这个目标,我们将使用 Erlang 的并发和分布式特性来构建一个可靠的系统。 阅读详情

相关推荐

ogame:由Erlang语言编写的游戏服务器

#Erlang game server 打造一个基于Erlang语言的分布式游戏服务器 ###整体设想大概会将服务器分为以下几大块: 网络模块: 分布式通信架构,整个网络模块要健壮,并发性高,能快速稳定地处理高并发的情况 日志系统: 一个日志应用,用于记录系统运行时的日志信息 数据库系统: 数据库选用mysql,应该会用到第三方库去连接,用一些进程池去处理IO操作 逻辑模块: 包含场景管理、怪物管理、人物管理、战斗逻辑等相关的游戏逻辑 项目编译和运行脚本都在'script'文件夹下,暂时只支持windows和linux两种系统编译 交流QQ群: 384132929

谈谈一只菜鸟转行Erlang游戏服务端的经历(希望大佬指导,也希望我的经历能给一些还未毕业的同学或者正在迷茫自己工作内容的同学一些感触)

第一次发文章,主要想谈谈自己近半年来的心路历程吧,希望各位大佬多多指教,也希望给看到这篇文章还未入行或者打算入行但是不知道选择什么方向的同学一点我自己的亲身体验。

GEM_boy的博客 2577

远古封神+英雄远征的ERLANG游戏服务器代码

看到另外两个分好高,我把另外两个二合一啦。远古封神+英雄远征的ERLANG游戏服务器代码,看过了,感觉不错的。

Erlang 游戏开发经验总结

https://www.fgba.net/sitemap.xml

august5291的博客 2264

erlang的小型游戏服务器

erlang单服游戏服务器,mnesia数据库,小型的游戏demo,编译可以启动,可以用来学习erlang游戏服务器相关的东西

深度学习入门:使用CMSIS-NN在微控制器上部署模型的完整指南与Python Jupyter实践

CMSIS-NN是ARM为Cortex-M系列微控制器设计的神经网络库。它旨在提供一套高效、轻量级的神经网络API,使得开发者可以在资源受限的微控制器上运行深度学习模型。CMSIS-NN优化了各种常见的神经网络层,如卷积层、全连接层等,确保它们在微控制器上的运行效率。# 定义模型])# 编译模型# 训练模型这样,我们就得到了一个简单的手写数字识别模型。注意:为了简洁和清晰,本文中的代码可能不是最优的或最完整的实现。为了获得完整的项目和更多的优化技巧,请下载完整项目。

m0_57781768的博客 5882

如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身(erlang)

附标题:如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身  原文:Writing Low-Pain Massively Scalable Multiplayer Servers  介绍  本文以我的OpenPoker项目为例子,讲述了一个构建超强伸缩性的在线多游戏玩家系统。  OpenPoker是一个超强多玩家纸牌服务器,具有容错、负载均衡和无限伸缩性等特性。

lynon的专栏 1038

用豆包+Skill从零制作AI漫剧:分镜、画面、配音到成片全流程

AI漫剧作为一种新兴内容形态,结合AI绘画与AI视频生成技术,正在改变短视频创作方式。其核心原理是利用提示词工程,将创意转化为结构化分镜脚本,再通过豆包等AI助手的Skill能力,将重复的脚本生成和分镜拆解流程固化为可复用的指令模板,从而大幅降低从构思到成品的生产门槛。这种模式无需剧组、演员和实景拍摄,让个人创作者也能借助图像生成、TTS配音与剪辑合成工具,批量化地生产剧情短片,适用于短视频平台连载、商业定制与个人IP打造。围绕豆包+Skill这条主线,从选题、剧本写作、分镜表设计,到画面提示词生成、视频片

weixin_29048309的博客 1481

如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身

原文:Writing Low-Pain Massively Scalable Multiplayer Servers 介绍 本文以我的OpenPoker项目为例子,讲述了一个构建超强伸缩性的在线多游戏玩家系统。 OpenPoker是一个超强多玩家纸牌服务器,具有容错、负载均衡和无限伸缩性等特性。 源代码位于我的个人站点上,大概10,000行代码,其中1/3是测试代码。 在OpenPoker...

資料為我做事 280

转载:YOLOv8改进全新Inner-IoU损失函数:扩展到其他SIoU、CIoU等主流损失函数,带辅助边界框的损失

目标检测是计算机视觉中的基本任务,包括目标分类和定位。边界框回归损失函数是检测器定位分支的重要组成部分,检测器的定位精度在很大程度上取决于边界框回归,在当前的检测器中发挥着不可替代的作用。在BBR中,IoU损失可以准确描述预测边界框与GT框之间匹配的程度,确保模型在训练过程中可以学习到目标的位置信息。作为现有主流边界框回归损失函数的基本部分,IoU定义如下:B和分别代表预测框和GT框。定义IoU之后,相应的损失可以定义如下:至今,基于IoU的损失函数逐渐成为主流并占据主导地位。

wuling129的专栏 4941

python气象数据可视化学习笔记8——利用matplotlib和ERA5数据绘制时间-高度气象综合廓线图

利用matplotlib和ERA5数据绘制时间-高度气象综合廓线图

qiuylulu的博客 8064

:如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身 ...

附标题:如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身 原文:Writing Low-Pain Massively Scalable Multiplayer Servers 介绍 本文以我的OpenPoker项目为例子,讲述了一个构建超强伸缩性的在线多游戏玩家系统。 OpenPoker是一个超强多玩家纸牌服务器,具有容错、负载均衡和无限伸缩性等特性。 ...

vanadiumlin 203

[南大ICS-PA2]PA2 - 简单复杂的机器:冯诺依曼计算机系统

mips32和riscv32的指令长度只有32位, 因此它们不能像x86那样, 把C代码中的32位常数直接编码到一条指令中. 思考一下, mips32和riscv32应该如何解决这个问题?加载立即数到寄存器的高20位,然后便可以是哟给你标准的立即指令来创建32位常量。在程序分析领域中,静态指令是指程序代码中的指令,动态指令是指程序运行过程中的指令,例如对于一下指令序列。位域,在小端机器上,先定义的在每个字节的低位,后定义的在每个字节的高位。,这是处理非法指令的宏,其定义在。指令,而下一条动态指令则是。

qq_42474104的博客 928

erlang 游戏服务器开发

最近关注erlang游戏服务器开发  erlang大牛写的游戏服务器值得参考 介绍本文以我的OpenPoker项目为例子,讲述了一个构建超强伸缩性的在线多游戏玩家系统。OpenPoker是一个超强多玩家纸牌服务器,具有容错、负载均衡和无限伸缩性等特性。源代码位于我的个人站点上,大概10,000行代码,其中1/3是测试代码。在OpenPoker最终版本敲定之前我做了大量调研,我尝试了Delp

slmeng2002的专栏 1万+

【人工智能】《Deep Dive into LLMs like ChatGPT 》—— Andrej Karpathy 第三阶段:强化学习(Reinforcement Learning, RL)

摘要:强化学习(RL)阶段通过让模型自主生成并验证答案,突破SFT阶段的模仿局限,使其在数学、代码等领域形成独特的推理路径。RL流程包括批量生成解答、自动批改筛选正确路径,并采用PPO/GRPO算法优化模型。模型会自发涌现自我检查、回滚等策略,显著提升正确率(如AIME竞赛准确率从15%升至56%)。与SFT模型相比,RL模型具备主动链式思维、验算能力,响应时间更长但效果更优,形成真正的“思考模型”。三阶段对比显示,RL通过可验证题的对错奖励机制,赋予模型超越人类范式的推理能力。

奶爸的编程之路,也就一周冷个三天 149

ESP32-C3模组上跑通HTTPS分次传输文件(1)

ESP32-C3模组上跑通HTTPS分次传输文件(1)

phmatthaus的专栏 759

华为云数据库自研黑科技,助推企业成本再降 50%

有个笑话,说某日下班后,某君带着一只宠物乌龟开车回家,在北京二环路上遭遇堵车高峰,半天走不了几步。乌龟耐不住性子,坚持要先爬回家去,主人只好由它去了。不知过了多久,主人在车里听见有敲门声,打开一看,只见乌龟满头冒汗,气鼓鼓地说:“你忘了给我家门钥匙 ……”   在大城市,我们饱受早晚高峰堵车的煎熬,如果道路可以根据车流量自行拓宽和收缩,那该有多好?当然,这在现实中绝无可能,但是,你的业务却可以...

shijin23的博客 383

Android 9.0 延时开机动画解决首次开机黑屏和去掉android正在启动的提示框

在9.0的系统产品rom定制化开发中,在一些产品中会出现在首次开机的时候,由于在开机动画播放完以后会出现几秒短暂的黑屏情况,然后进入默认Launcher,这在产品体验上 也是感觉到有点差,所以会要求在去掉这个首次开机黑屏的效果,和在启动过程中的 android is starting这个提示框的这些效果优化,接下来就分析下相关功能, 然后实现这个功能的开发

安卓兼职framework和app工程师的博客 3244

升讯威在线客服系统的并发高性能数据处理技术:超强的 SignalR

客户组织多名客服上线后,所有员工**同一时间**打开访客页面**疯狂不停**的给在线客服发消息,系统稳定**无异常无掉线**,客服回复消息正常。消息**实时到达**无任何延迟。我会通过一系列的文章详细分析升讯威在线客服系统的并发高性能技术是如何实现的,使用了哪些方案以及具体的做法。

631

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

一文读懂超级云 App:比普通 App 强在哪?未来应用场景不可限量

【摘要】超级云App是基于云计算的新型应用形态,将数据存储和计算转移到云端,实现跨设备访问和实时同步。其核心优势包括:强大的云端计算能力打破设备性能限制、弹性扩展满足不同需求、多重保障确保数据安全、以及多终端无缝衔接提升体验。相比传统App,超级云App在运行环境、部署维护、可扩展性等方面具有显著差异,采用按需付费模式降低使用门槛。随着技术发展,超级云App将在个人数字管理、企业协同办公及教育医疗等领域发挥更大价值,成为数字化时代的重要工具。

2501_93088530的博客 2351

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: Joe Armstrong:关于并行编程和Erlang的十个问题
下一篇: OTP Design Principles Overview
hidetobj
博客等级 码龄19年 16粉丝 301原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值