99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

actor模型的設(shè)計(jì)原理和使用

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-10 11:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一、多核并發(fā)編程方式

(1)多線程。

在一個(gè)進(jìn)程中開啟多線程,為了充分利用多核,一般設(shè)置工作線程的個(gè)數(shù)為 cpu 的核心數(shù)。memcached 就是采用這種方式。

多線程在一個(gè)進(jìn)程當(dāng)中,所以數(shù)據(jù)共享來自進(jìn)程當(dāng)中的虛擬內(nèi)存;這里會涉及到很多臨界資源的訪問,所以需要考慮加鎖。

(2)多進(jìn)程。

在一臺機(jī)器當(dāng)中,開啟多個(gè)進(jìn)程充分利用多核,一般設(shè)置工作進(jìn)程的個(gè)數(shù)為 cpu 的核心數(shù)。nginx 就是采用這種方式,nginx 當(dāng)中的 worker 進(jìn)程,通過共享內(nèi)存來進(jìn)行共享數(shù)據(jù);也需要考慮使用鎖。

(3)CSP。

以 go 語言為代表,并發(fā)實(shí)體是協(xié)程(用戶態(tài)線程、輕量級線程);內(nèi)部也是采用多少個(gè)核心開啟多少個(gè)線程來充分利用多核。

(4)Actor。

erlang 從語言層面支持 actor 并發(fā)模型,并發(fā)實(shí)體是 actor(在skynet 中稱之為服務(wù));skynet 采用 c + lua來實(shí)現(xiàn) actor 并發(fā)模型;底層也是通過采用多少個(gè)核心開啟多少個(gè)內(nèi)核線程來充分利用多核。

二、skynet

2.1、skynet簡介

它是一個(gè)輕量級游戲服務(wù)器框架,但也不僅僅用于游戲。

輕量級體現(xiàn)在:

  1. 實(shí)現(xiàn)了 actor 模型,以及相關(guān)的腳手架(工具集):actor 間數(shù)據(jù)共享機(jī)制以及c 服務(wù)擴(kuò)展機(jī)制。
  2. 實(shí)現(xiàn)了服務(wù)器框架的基礎(chǔ)組件。實(shí)現(xiàn)了 reactor 并發(fā)網(wǎng)絡(luò)庫;并提供了大量連接的接入方案;基于自身網(wǎng)絡(luò)庫,實(shí)現(xiàn)了常用的數(shù)據(jù)庫驅(qū)動(異步連接方案),并融合了 lua 數(shù)據(jù)結(jié)構(gòu);實(shí)現(xiàn)了網(wǎng)關(guān)服務(wù);時(shí)間輪用于處理定時(shí)消息。

skynet抽象了actor并發(fā)模型,用戶層抽象進(jìn)程;sknet通過消息的方式共享內(nèi)存;通過消息驅(qū)動actor運(yùn)行。

skynet的actor模型使用lua虛擬,lua虛擬機(jī)非常?。ㄖ挥袔资甼b),代價(jià)不高;每個(gè)actor對應(yīng)一個(gè)lua虛擬機(jī);系統(tǒng)中不能啟動過多的進(jìn)程就是因?yàn)橘Y源受限,lua虛擬機(jī)占用的資源很少,可以開啟很多個(gè),這就能抽象出很多個(gè)用戶層的進(jìn)程。lua虛擬機(jī)可以共享一些數(shù)據(jù),比如常量,達(dá)到資源復(fù)用。

抽象進(jìn)程而不抽象線程的原因在于進(jìn)程有獨(dú)立的工作空間,隔離的運(yùn)行環(huán)境。

sknet的所有actor都是對等的,通過公平調(diào)度實(shí)現(xiàn)。

2.2、環(huán)境準(zhǔn)備

ubuntu:

sudo apt-get install git build-essential readline-dev autoconf
# 或者
sudo apt-get install git build-essential libreadline-dev autoconf

centos:

yum install -y git gcc readline-devel autoconf

mac:

yum install -y git gcc readline-devel autoconf

2.3、編譯安裝

git clone https://github.com/cloudwu/skynet.git
cd skynet
# centos or ubuntu
make linux
# mac
make macosx

2.4、Actor 模型

有消息的 actor 為活躍的 actor,沒有消息為非活躍的 actor。

定義:

  1. 用于并行計(jì)算;
  2. Actor 是最基本的計(jì)算單元;
  3. 基于消息計(jì)算;
  4. Actor 通過消息進(jìn)行溝通。

組成:

  1. 隔離的環(huán)境。主要通過 lua 虛擬機(jī)來實(shí)現(xiàn)。
  2. 消息隊(duì)列。用來存放有序(先后到達(dá))的消息。
  3. 回調(diào)函數(shù)。用來運(yùn)行 Actor;從 Actor 的消息隊(duì)列中取出消息,并作為該回調(diào)函數(shù)的參數(shù)來運(yùn)行 Actor。

2.5、消息隊(duì)列

Actor 模型基于消息計(jì)算,在 skynet 框架中,消息包含 Actor(之間)消息、網(wǎng)絡(luò)消息以及定時(shí)消息。

生產(chǎn)者生產(chǎn)消息,消息放入消息隊(duì)列中,由線程池去消費(fèi)消息。

2.6、actor公平調(diào)度

所有的actor都是對等的,每個(gè)actor都有自己的消息隊(duì)列;skynet的并發(fā)實(shí)體是actor,因此需要公平的調(diào)度actor。

skynet會有非常的actor,公平調(diào)度就非常重要;采用兩級隊(duì)列。

首先,查找活躍的消息隊(duì)列(有消息的消息隊(duì)列);

然后,通過隊(duì)列組織所有活躍的消息隊(duì)列;

最后,調(diào)度隊(duì)列。

圖片

線程池從一級隊(duì)列取出一個(gè)消息,消費(fèi)消息,消費(fèi)完消息后如果還有消息,則添加到一級隊(duì)列的末尾。因?yàn)橛脩魡栴}造成消息不均勻,在應(yīng)用上不一定公平;skynet在工作線程賦予權(quán)重來解決這個(gè)問題。

// 工作線程權(quán)重圖 32個(gè)核心
static int weight[] = {
-1, -1, -1, -1, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, // 1/2
2, 2, 2, 2, 2, 2, 2, 2, // 1/4
3, 3, 3, 3, 3, 3, 3, 3, }; // 1/8

當(dāng)工作線程的權(quán)重為 -1 時(shí),該工作線程每次只 pop 一條消息;當(dāng)工作線程的權(quán)重為 0 時(shí),該工作線程每次消費(fèi)完所有的消息;當(dāng)工作線程的權(quán)重為 1 時(shí),每次消費(fèi)消息隊(duì)列中二分之一的消息;當(dāng)工作線程的權(quán)重為 2 時(shí),每次消費(fèi)消息隊(duì)列中四分之一 的消息;以此類推;通過這種方式,完成消息隊(duì)列梯度消費(fèi),從而不至于讓某些隊(duì)列過長。

三、skynet的使用

github 上打開 skynet 點(diǎn)擊 wiki 里面有所有函數(shù)的詳細(xì)說明。

3.1、第一個(gè)skynet程序

(1)在sknet源碼的父目錄下創(chuàng)建一個(gè)config文件,用于定制skynet的行為。 內(nèi)容可參考如下:

thread=4
logger=nil
harbor=0
start="main"
lua_path="./skynet/lualib/?.lua;./skynet/lualib/?/init.lua;"
luaservice="./skynet/service/?.lua;./app/?.lua"
lualoader="./skynet/lualib/loader.lua"
cpath="./skynet/cservice/?.so"
lua_cpath="./skynet/luaclib/?.so"

參數(shù)說明:

圖片

(2)在app文件下面創(chuàng)建main.lua。每次啟動時(shí)都是從skynet.start(…)中運(yùn)行,相當(dāng)于入口函數(shù)。

local skynet = require("skynet")

skynet.start(function()
-- body
print("hello skynet")
end)

(3)編寫一個(gè)自己項(xiàng)目的makefile。首先編譯skynet的源碼,如果有自己的c代碼直接加入makefile文件。

SKYNET_PATH?=./skynet

all:
cd $(SKYNET_PATH) && $(MAKE) PLAT='linux'

clean:
cd $(SKYNET_PATH) && $(MAKE) clean

(4)編譯,執(zhí)行自己的makefile。

make

(5)執(zhí)行skynet,指定config。

./skynet/skynet config
[:00000002] LAUNCH snlua bootstrap
[:00000003] LAUNCH snlua launcher
[:00000004] LAUNCH snlua cdummy
[:00000005] LAUNCH harbor 0 4
[:00000006] LAUNCH snlua datacenterd
[:00000007] LAUNCH snlua service_mgr
[:00000008] LAUNCH snlua main
hello skynet
[:00000002] KILL self

可以看到打印了hello skynet。

3.2、skynet網(wǎng)絡(luò)消息

skynet 當(dāng)中采用一個(gè) socket 線程來處理網(wǎng)絡(luò)信息;skynet 基于 reactor 網(wǎng)絡(luò)模型。

網(wǎng)絡(luò)消息驅(qū)動actor運(yùn)行。需要skynet.socket模塊。

首先綁定一個(gè)監(jiān)聽 listenfd,然后調(diào)用socket.start(listenfd, function)綁定fd到進(jìn)程函數(shù)function中處理。

示例:

main.lua

local skynet = require "skynet"
local socket=require "skynet.socket"


skynet.start(function()
-- body
print("hello skynet")

local listenfd=socket.listen("0.0.0.0",8888);
socket.start(listenfd,function(clientfd,addr)
-- body
print("receive a client: ",clientfd,addr);
end)

end)
[:00000002] LAUNCH snlua bootstrap
[:00000003] LAUNCH snlua launcher
[:00000004] LAUNCH snlua cdummy
[:00000005] LAUNCH harbor 0 4
[:00000006] LAUNCH snlua datacenterd
[:00000007] LAUNCH snlua service_mgr
[:00000008] LAUNCH snlua main
hello skynet
[:00000002] KILL self
receive a client: 2 192.168.0.105:50024

3.3、skynet定時(shí)消息

定時(shí)任務(wù)推送給定時(shí)線程,定時(shí)線程檢測完時(shí)間后往消息隊(duì)列推送一個(gè)消息,然后actor開始執(zhí)行callback函數(shù)。

使用示例: main.lua

local skynet = require "skynet"


skynet.start(function()
-- body
print("hello skynet")
skynet.timeout(100,function()
-- body
print("timer 1s");
end)

end)

3.4、skynet actor間消息

所有的服務(wù)都是通過消息來交換數(shù)據(jù)。actor間消息通信通過將消息放到對方的消息隊(duì)列實(shí)現(xiàn)。

示例,創(chuàng)建兩個(gè)lua文件。

main發(fā)送“ping”給slave,協(xié)程掛起;slave回復(fù)“pong”給main,協(xié)程喚醒。整個(gè)過程使用協(xié)程實(shí)現(xiàn)異步操作,消除異步中的回調(diào)。

main.lua

local skynet = require("skynet")

skynet.start(function()
-- body
print("hello skynet")

local slave=skynet.newservice("slave")
local response=skynet.call(slave,"lua","ping")
print("main ",response)
end)

slave.lua

local skynet = require "skynet"

local CMD={}

function CMD.ping()
-- body
skynet.retpack("pong")
end

skynet.start(function()
skynet.dispatch("lua",function(session,source,cmd,...)
local func=assert(CMD[cmd])
func(...)
end)
end)

執(zhí)行效果:

[:00000002] LAUNCH snlua bootstrap
[:00000003] LAUNCH snlua launcher
[:00000004] LAUNCH snlua cdummy
[:00000005] LAUNCH harbor 0 4
[:00000006] LAUNCH snlua datacenterd
[:00000007] LAUNCH snlua service_mgr
[:00000008] LAUNCH snlua main
hello skynet
[:00000009] LAUNCH snlua slave
main pong
[:00000002] KILL self

四、vscode調(diào)試skynet

首先要知道整個(gè)系統(tǒng)/框架 是怎么應(yīng)用的。skynet會自己產(chǎn)生一個(gè)skynet執(zhí)行程序,需要指定配置文件來啟動服務(wù)。

項(xiàng)目下的.vscode文件夾需要如下三個(gè)文件。

launch.json

{
"version": "0.2.0",
"configurations": [
{
"name": "啟動 app",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/skynet/skynet",
"args": ["config"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "為 gdb 啟用整齊打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "將反匯編風(fēng)格設(shè)置為 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "build-skynet",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}

settings.json

{
"C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools",
"files.associations": {
"string.h": "c",
"stdlib.h": "c",
"pthread.h": "c"
},
}

tasks.json

{
"tasks": [
{
"type": "cppbuild",
"label": "build-skynet",
"command": "/usr/bin/make",
"args": [],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "..."
}
],
"version": "2.0.0"
}

實(shí)現(xiàn)這三個(gè)文件就可以開始調(diào)試了。

skynet是一個(gè)網(wǎng)絡(luò)服務(wù),需要處理網(wǎng)絡(luò)連接,需要知道數(shù)據(jù)是怎么流向,理解框架的運(yùn)行機(jī)制(多線程并發(fā));所有的actor的運(yùn)行都是由線程池來驅(qū)動,actor的運(yùn)行又是由消息隊(duì)列的消息驅(qū)動(網(wǎng)絡(luò)消息、定時(shí)消息、actor間消息)。

線程池從消息隊(duì)列中取出消息,找到回調(diào)函數(shù),驅(qū)動actor運(yùn)行。

總結(jié)

不要通過共享內(nèi)存來通信,而應(yīng)該通過通信來共享內(nèi)存。CSP 和 Actor 都符合這一哲學(xué);通過通信來共享數(shù)據(jù),其實(shí)是一種解耦合的過程。并lua發(fā)實(shí)體之間可以分別開發(fā)并單獨(dú)優(yōu)化,而它們唯一的耦合在于消息;這能讓我們快速地進(jìn)行開發(fā);同時(shí)也符合我們開發(fā)的思路,將一個(gè)大的問題拆分成若干個(gè)小問題。

actor模型是在用戶層抽象了進(jìn)程。

actor調(diào)度:將活躍的 actor 通過全局隊(duì)列組織起來;actor 當(dāng)中的消息隊(duì)列有消息就是活躍的 actor; 線程池去全局隊(duì)列中取出 actor 的消息隊(duì)列,接著運(yùn)行actor。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    13

    文章

    9796

    瀏覽量

    88015
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3125

    瀏覽量

    75280
  • 模型
    +關(guān)注

    關(guān)注

    1

    文章

    3521

    瀏覽量

    50444
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    966

    瀏覽量

    29377
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    ActorFramework開發(fā)實(shí)例-用戶管理模塊

    本帖最后由 asdxxw1874 于 2025-6-9 14:23 編輯 (1)Actor模型介紹 Actor模型是1973年提出的一個(gè)分布式并發(fā)編程模式,在Erlang語言中得
    發(fā)表于 08-16 14:23

    鴻蒙ArkTS的起源和簡介

    設(shè)備甚至異構(gòu)芯片是一個(gè)重要的課題。目前我們采用的仍然是業(yè)界常見的類Actor模型的并發(fā)接口——Worker,它彌補(bǔ)了Actor模型的些許劣勢,即允許用戶轉(zhuǎn)移和共享大量的Buffer以避
    發(fā)表于 01-16 16:23

    鴻蒙原生應(yīng)用開發(fā)-ArkTS語言基礎(chǔ)類庫多線程并發(fā)概述

    并發(fā)模型是用來實(shí)現(xiàn)不同應(yīng)用場景中并發(fā)任務(wù)的編程模型,常見的并發(fā)模型分為基于內(nèi)存共享的并發(fā)模型和基于消息通信的并發(fā)模型。
    發(fā)表于 03-22 15:40

    鴻蒙原生應(yīng)用開發(fā)-ArkTS語言基礎(chǔ)類庫多線程并發(fā)概述

    并發(fā)模型是用來實(shí)現(xiàn)不同應(yīng)用場景中并發(fā)任務(wù)的編程模型,常見的并發(fā)模型分為基于內(nèi)存共享的并發(fā)模型和基于消息通信的并發(fā)模型
    發(fā)表于 03-28 14:35

    [Actor] 通過actor創(chuàng)建控制中心與數(shù)據(jù)采集工作站來看操作者架構(gòu)

    *附件:面向?qū)ο笤囼?yàn)機(jī)測控系統(tǒng).zip 一、actor對象描述 1、actor對象本身就是一個(gè)隊(duì)列狀態(tài)機(jī)類,空白的一個(gè)對象即具備了隊(duì)列狀態(tài)機(jī)功能。但是具備不代表無條件立即運(yùn)行;這些功能必須在幾個(gè)關(guān)鍵
    發(fā)表于 05-14 18:44

    sushu---Actor Framework基本介紹

    一練]Actor Framework框架(1125-1201)2016-02-28 20:15:20新寫的一篇帖子:sushu---Actor Framework一種使用方式主貼里面循序漸進(jìn)的介紹了一些信息?,F(xiàn)在
    發(fā)表于 01-03 20:05

    ActorFramework在測控設(shè)備上的應(yīng)用

    Actor模型是1973年提出的一個(gè)分布式并發(fā)編程模式,在Erlang語言中得到廣泛支持和應(yīng)用。在Actor模型中,Actor參與者是一個(gè)并
    發(fā)表于 05-27 09:04

    Actor框架介紹

    Actor Framework是一個(gè)軟件類庫,適用于多線程應(yīng)用程序,每個(gè)操作者(Actors)執(zhí)行獨(dú)立的線程任務(wù),操作者本身可以傳遞消息也可以在操作者之間傳遞消息。1.右鍵我的電腦新建--操作者2.
    發(fā)表于 01-13 22:10

    labview actor framework問題

    我按照網(wǎng)上提供的歷程,編了一個(gè)代碼,但是運(yùn)行時(shí)一直處于actor core.vi,請大神幫忙看一下
    發(fā)表于 09-24 21:55

    Lite Actor:方舟Actor并發(fā)模型的輕量級優(yōu)化

    設(shè)備的不斷增多,并發(fā)模型顯得舉足輕重,本期我們將為大家?guī)矸街劬幾g器對傳統(tǒng)Actor并發(fā)模型的輕量級優(yōu)化。 一、什么是并發(fā)模型?在操作系統(tǒng)中,并發(fā)是任務(wù)在不影響最終執(zhí)行結(jié)果的情況下無序
    發(fā)表于 07-18 12:00

    不同設(shè)備如何統(tǒng)一語言編程平臺高效開發(fā)?本文為你揭秘

    。 三、ArkCompiler的并發(fā)亮點(diǎn) 并發(fā)實(shí)例運(yùn)行對比 3.1 業(yè)界JS引擎的Actor并發(fā)模型 上圖左側(cè)是業(yè)界并發(fā)實(shí)例的運(yùn)行情況,由于JS是一門單線程語言,JS引擎在設(shè)計(jì)之初也沒有考慮多線程運(yùn)行
    發(fā)表于 05-09 10:01

    移動應(yīng)用高級語言開發(fā)——并發(fā)探索

    多核架構(gòu) 2.2??Actor 模型 Actor模型概念的提出已經(jīng)幾十年了:一個(gè)actor是一個(gè)基本的計(jì)算單元,通過消息通信;內(nèi)部維持可變
    發(fā)表于 08-28 17:08

    七種常見的并發(fā)編程模型簡介

    。函數(shù)式編程消除了可變狀態(tài),所以從根本上是線程安全的,而且易于并行執(zhí)行。 3. Clojure之道分離標(biāo)識與狀態(tài) 編程語言Clojure是一種指令式編程和函數(shù)式編程的混搭方案,在兩種編程方式上取得了微妙的平衡來發(fā)揮兩者的優(yōu)勢。 4. actor actor
    的頭像 發(fā)表于 03-15 17:21 ?4912次閱讀

    關(guān)于Actor并發(fā)模型的解析

    設(shè)備的不斷增多,并發(fā)模型顯得舉足輕重,本期我們將為大家?guī)矸街劬幾g器對傳統(tǒng)Actor并發(fā)模型的輕量級優(yōu)化。
    的頭像 發(fā)表于 07-18 09:23 ?2388次閱讀

    在LabVIEW中創(chuàng)建Actor Framework的抽象消息及接口

    由于面向?qū)ο笮枰档婉詈闲?,那么基于類的操作者也需要考慮如何降低耦合性。當(dāng)Nest Actor給Root Actor發(fā)送消息時(shí),需要調(diào)用Root Actor的消息類的Send ***.vi,這就導(dǎo)致了Nest
    的頭像 發(fā)表于 09-23 10:51 ?8687次閱讀