
Gabatarwar
(zare guda ɗaya ) samfuri ne don rubuta software mai ɗaukar nauyi, ana amfani da shi a cikin shahararrun mafita da yawa:
- ...
A cikin wannan labarin, za mu dubi abubuwan da ke cikin na'urar reactor na I/O da yadda yake aiki, rubuta aiwatarwa a cikin ƙasa da layi na 200, da kuma yin tsari mai sauƙi na HTTP akan buƙatun miliyan 40 / min.
Magana
- An rubuta labarin don taimakawa fahimtar aikin I/O reactor, don haka fahimtar kasada lokacin amfani da shi.
- Ana buƙatar ilimin abubuwan asali don fahimtar labarin. da wasu gogewa a cikin haɓaka aikace-aikacen cibiyar sadarwa.
- An rubuta duk lambar a cikin yaren C daidai gwargwadon (hankali: dogon PDF) don Linux kuma akwai akan .
Me yasa wannan ya zama dole?
Tare da karuwar shaharar Intanet, sabobin yanar gizo sun fara buƙatar ɗaukar adadin haɗin kai lokaci guda, sabili da haka an gwada hanyoyin guda biyu: toshe I / O akan babban adadin zaren OS da rashin toshe I / O a hade tare da tsarin sanarwar taron, wanda kuma ake kira “System selector” (///da sauransu).
Hanya ta farko ta ƙunshi ƙirƙirar sabon zaren OS don kowane haɗin da ke shigowa. Rashin hasaransa shine rashin daidaituwa mara kyau: tsarin aiki zai aiwatar da yawa и . Suna aiki mai tsada kuma suna iya haifar da rashin RAM kyauta tare da adadin haɗin kai mai ban sha'awa.
Sigar da aka gyara tana haskakawa (Pool pool), don haka hana tsarin daga zubar da kisa, amma a lokaci guda gabatar da wata sabuwar matsala: idan wani thread pool a halin yanzu an katange ta da dogon karanta ayyukan, sa'an nan sauran kwasfa da suka riga sun sami damar samun bayanai ba za su iya. yi haka.
Hanya ta biyu tana amfani (System selector) wanda OS ke bayarwa. Wannan labarin ya tattauna mafi yawan nau'in zaɓen tsarin, dangane da faɗakarwa (al'amuran, sanarwa) game da shirye-shiryen ayyukan I/O, maimakon a kunne. . Misali mai sauƙaƙan amfani da shi ana iya wakilta shi ta hanyar toshe zane mai zuwa:

Bambancin waɗannan hanyoyin shine kamar haka:
- Toshe ayyukan I/O dakatar mai amfani kwarara har zuwahar sai OS ɗin ya dace mai shigowa zuwa byte stream (, karɓar bayanai) ko kuma ba za a sami isasshen sarari a cikin maƙallan rubutu na ciki don aikawa ta gaba ba. (aikawa data).
- Mai zaɓin tsarin akan lokaci sanar da shirin cewa OS riga fakitin IP masu lalacewa (TCP, liyafar bayanai) ko isasshen sarari a cikin buffers na rubutu na ciki riga samuwa (aika bayanai).
A taƙaice, ajiye zaren OS ga kowane I/O ɓarna ce ta ikon sarrafa kwamfuta, saboda a zahiri, zaren ba sa yin aiki mai amfani (wannan shine inda kalmar ta fito daga. ). Mai zaɓin tsarin yana magance wannan matsala, yana ƙyale shirin mai amfani yayi amfani da albarkatun CPU fiye da tattalin arziki.
I/O reactor model
Reactor I/O yana aiki azaman Layer tsakanin mai zaɓin tsarin da lambar mai amfani. An kwatanta ka'idar aikinsa ta hanyar zane mai zuwa:

- Bari in tunatar da ku cewa taron sanarwa ne cewa wani soket yana iya yin aikin I/O mara toshewa.
- Mai sarrafa taron aiki ne da ake kira da reactor na I/O lokacin da aka karɓi wani abu, wanda sai yayi aikin I/O mara toshewa.
Yana da mahimmanci a lura cewa reactor na I/O shine ta ma'anar zaren guda ɗaya, amma babu wani abu da zai hana ra'ayin yin amfani da shi a cikin mahalli da yawa a cikin rabon zaren 1: 1 reactor, don haka ana sake yin amfani da duk nau'ikan CPU.
Aiwatarwa
Za mu sanya haɗin gwiwar jama'a a cikin fayil , da aiwatarwa - in . reactor.h za ta ƙunshi sanarwa kamar haka:
Nuna sanarwa a cikin reactor.h
typedef struct reactor Reactor;
/*
* Указатель на функцию, которая будет вызываться I/O реактором при поступлении
* события от системного селектора.
*/
typedef void (*Callback)(void *arg, int fd, uint32_t events);
/*
* Возвращает `NULL` в случае ошибки, не-`NULL` указатель на `Reactor` в
* противном случае.
*/
Reactor *reactor_new(void);
/*
* Освобождает системный селектор, все зарегистрированные сокеты в данный момент
* времени и сам I/O реактор.
*
* Следующие функции возвращают -1 в случае ошибки, 0 в случае успеха.
*/
int reactor_destroy(Reactor *reactor);
int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
Callback callback, void *callback_arg);
int reactor_deregister(const Reactor *reactor, int fd);
int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
Callback callback, void *callback_arg);
/*
* Запускает цикл событий с тайм-аутом `timeout`.
*
* Эта функция передаст управление вызывающему коду если отведённое время вышло
* или/и при отсутствии зарегистрированных сокетов.
*/
int reactor_run(const Reactor *reactor, time_t timeout);Tsarin reactor na I/O ya ƙunshi mai zaɓe и , wanda ke yin taswirar kowane soket zuwa CallbackData (tsarin mai sarrafa taron da hujjar mai amfani da shi).
Nuna Reactor da CallbackData
struct reactor {
int epoll_fd;
GHashTable *table; // (int, CallbackData)
};
typedef struct {
Callback callback;
void *arg;
} CallbackData;Lura cewa mun ba da damar iyawa bisa ga index. IN reactor.h mun bayyana tsarin reactor, kuma cikin reactor.c mun ayyana shi, ta haka ne za mu hana mai amfani da shi canza filayensa a sarari. Wannan yana ɗaya daga cikin alamu , wanda ya dace daidai da fassarar C.
Ayyuka reactor_register, reactor_deregister и reactor_reregister sabunta jerin kwasfa na sha'awa da masu gudanar da taron daidai a cikin mai zaɓin tsarin da tebur ɗin zanta.
Nuna ayyukan rajista
#define REACTOR_CTL(reactor, op, fd, interest)
if (epoll_ctl(reactor->epoll_fd, op, fd,
&(struct epoll_event){.events = interest,
.data = {.fd = fd}}) == -1) {
perror("epoll_ctl");
return -1;
}
int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
Callback callback, void *callback_arg) {
REACTOR_CTL(reactor, EPOLL_CTL_ADD, fd, interest)
g_hash_table_insert(reactor->table, int_in_heap(fd),
callback_data_new(callback, callback_arg));
return 0;
}
int reactor_deregister(const Reactor *reactor, int fd) {
REACTOR_CTL(reactor, EPOLL_CTL_DEL, fd, 0)
g_hash_table_remove(reactor->table, &fd);
return 0;
}
int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
Callback callback, void *callback_arg) {
REACTOR_CTL(reactor, EPOLL_CTL_MOD, fd, interest)
g_hash_table_insert(reactor->table, int_in_heap(fd),
callback_data_new(callback, callback_arg));
return 0;
}Bayan reactor na I/O ya katse taron tare da mai bayanin fd, yana kiran mai kula da taron daidai, wanda ya wuce fd, abubuwan da aka haifar da alamar mai amfani zuwa void.
Nuna aikin reactor_run().
int reactor_run(const Reactor *reactor, time_t timeout) {
int result;
struct epoll_event *events;
if ((events = calloc(MAX_EVENTS, sizeof(*events))) == NULL)
abort();
time_t start = time(NULL);
while (true) {
time_t passed = time(NULL) - start;
int nfds =
epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, timeout - passed);
switch (nfds) {
// Ошибка
case -1:
perror("epoll_wait");
result = -1;
goto cleanup;
// Время вышло
case 0:
result = 0;
goto cleanup;
// Успешная операция
default:
// Вызвать обработчиков событий
for (int i = 0; i < nfds; i++) {
int fd = events[i].data.fd;
CallbackData *callback =
g_hash_table_lookup(reactor->table, &fd);
callback->callback(callback->arg, fd, events[i].events);
}
}
}
cleanup:
free(events);
return result;
}Don taƙaitawa, jerin kira na aiki a lambar mai amfani zai ɗauki nau'i mai zuwa:

Uwar garken zaren guda ɗaya
Domin gwada reactor na I/O a ƙarƙashin babban nauyi, za mu rubuta sabar gidan yanar gizo mai sauƙi ta HTTP wanda ke amsa kowane buƙatu tare da hoto.
Magana mai sauri ga ka'idar HTTP
- wannan shine ka'idar , da farko ana amfani dashi don hulɗar uwar garken-browser.
Ana iya amfani da HTTP cikin sauƙi yarjejeniya , aikawa da karɓar saƙonni a cikin sigar da aka ƙayyade .
Tsarin nema
<КОМАНДА> <URI> <ВЕРСИЯ HTTP>CRLF
<ЗАГОЛОВОК 1>CRLF
<ЗАГОЛОВОК 2>CRLF
<ЗАГОЛОВОК N>CRLF CRLF
<ДАННЫЕ>CRLFjerin haruffa biyu ne:rиn, raba layin farko na buƙatun, rubutun kai da bayanai.<КОМАНДА>- daya dagaCONNECT,DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT,TRACE. Mai lilo zai aika umarni zuwa uwar garken muGET, ma'ana "Aika mini abinda ke cikin fayil ɗin."<URI>- . Misali, idan URI =/index.html, sannan abokin ciniki ya bukaci babban shafin yanar gizon.<ВЕРСИЯ HTTP>- sigar ka'idar HTTP a cikin tsariHTTP/X.Y. Sigar da aka fi amfani da ita a yau ita ceHTTP/1.1.<ЗАГОЛОВОК N>maɓalli ne-darajar biyu a cikin tsari<КЛЮЧ>: <ЗНАЧЕНИЕ>, aika zuwa uwar garken don ƙarin bincike.<ДАННЫЕ>- bayanan da uwar garken ke buƙata don yin aikin. Sau da yawa yana da sauƙi ko wani tsari.
Tsarin amsawa
<ВЕРСИЯ HTTP> <КОД СТАТУСА> <ОПИСАНИЕ СТАТУСА>CRLF
<ЗАГОЛОВОК 1>CRLF
<ЗАГОЛОВОК 2>CRLF
<ЗАГОЛОВОК N>CRLF CRLF
<ДАННЫЕ><КОД СТАТУСА>lamba ce dake wakiltar sakamakon aikin. Sabar mu koyaushe zata dawo da matsayi 200 (aikin nasara).<ОПИСАНИЕ СТАТУСА>- wakilcin kirtani na lambar matsayi. Don lambar matsayi 200 wannan shineOK.<ЗАГОЛОВОК N>- taken tsari iri ɗaya kamar a cikin buƙatun. Za mu mayar da takenContent-Length(girman fayil) kumaContent-Type: text/html(nau'in bayanan dawowa).<ДАННЫЕ>- bayanan da mai amfani ya nema. A cikin yanayinmu, wannan ita ce hanyar zuwa hoton a ciki .
fayil (uwar garken zaren guda ɗaya) ya haɗa da fayil , wanda ya ƙunshi samfurori masu zuwa:
Nuna samfuran ayyuka a gama-gari.h
/*
* Обработчик событий, который вызовется после того, как сокет будет
* готов принять новое соединение.
*/
static void on_accept(void *arg, int fd, uint32_t events);
/*
* Обработчик событий, который вызовется после того, как сокет будет
* готов отправить HTTP ответ.
*/
static void on_send(void *arg, int fd, uint32_t events);
/*
* Обработчик событий, который вызовется после того, как сокет будет
* готов принять часть HTTP запроса.
*/
static void on_recv(void *arg, int fd, uint32_t events);
/*
* Переводит входящее соединение в неблокирующий режим.
*/
static void set_nonblocking(int fd);
/*
* Печатает переданные аргументы в stderr и выходит из процесса с
* кодом `EXIT_FAILURE`.
*/
static noreturn void fail(const char *format, ...);
/*
* Возвращает файловый дескриптор сокета, способного принимать новые
* TCP соединения.
*/
static int new_server(bool reuse_port);An kuma bayyana macro mai aiki SAFE_CALL() kuma an ayyana aikin fail(). Macro yana kwatanta ƙimar magana tare da kuskure, kuma idan yanayin gaskiya ne, ya kira aikin fail():
#define SAFE_CALL(call, error)
do {
if ((call) == error) {
fail("%s", #call);
}
} while (false)aiki fail() yana buga muhawarar da aka wuce zuwa tashar (kamar ) kuma ya ƙare shirin tare da lambar EXIT_FAILURE:
static noreturn void fail(const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, ": %sn", strerror(errno));
exit(EXIT_FAILURE);
}aiki new_server() yana dawo da bayanin fayil na soket "uwar garken" wanda aka ƙirƙira ta hanyar kiran tsarin , и kuma mai ikon karɓar haɗin kai masu shigowa cikin yanayin da ba tare da toshewa ba.
Nuna aikin new_server().
static int new_server(bool reuse_port) {
int fd;
SAFE_CALL((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)),
-1);
if (reuse_port) {
SAFE_CALL(
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)),
-1);
}
struct sockaddr_in addr = {.sin_family = AF_INET,
.sin_port = htons(SERVER_PORT),
.sin_addr = {.s_addr = inet_addr(SERVER_IPV4)},
.sin_zero = {0}};
SAFE_CALL(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), -1);
SAFE_CALL(listen(fd, SERVER_BACKLOG), -1);
return fd;
}- Lura cewa an fara ƙirƙiri soket ɗin a cikin yanayin da ba tare da toshewa ba ta amfani da tuta
SOCK_NONBLOCKdon haka a cikin aikinon_accept()(kara karantawa) kiran tsarinaccept()bai daina aiwatar da zaren ba. - idan
reuse_portdaidai yake datrue, to wannan aikin zai saita soket tare da zaɓi ta hanyar don amfani da tashar tashar jiragen ruwa guda ɗaya a cikin mahalli mai zare da yawa (duba sashe "Sabar-Treaded Multi-threaded").
Mai Gudanar da Taron on_accept() da ake kira bayan OS ya haifar da wani taron EPOLLIN, a wannan yanayin yana nufin cewa za a iya karɓar sabon haɗin. on_accept() yana karɓar sabon haɗi, yana canza shi zuwa yanayin da ba tare da toshewa ba kuma yayi rijista tare da mai sarrafa taron on_recv() a cikin I/O reactor.
Nuna akan_accept() aikin
static void on_accept(void *arg, int fd, uint32_t events) {
int incoming_conn;
SAFE_CALL((incoming_conn = accept(fd, NULL, NULL)), -1);
set_nonblocking(incoming_conn);
SAFE_CALL(reactor_register(reactor, incoming_conn, EPOLLIN, on_recv,
request_buffer_new()),
-1);
}Mai Gudanar da Taron on_recv() da ake kira bayan OS ya haifar da wani taron EPOLLIN, a wannan yanayin yana nufin cewa haɗin ya yi rajista on_accept(), shirye don karɓar bayanai.
on_recv() yana karanta bayanai daga haɗin kai har sai an karɓi buƙatar HTTP gaba ɗaya, sannan ta yi rajistar mai sarrafa on_send() don aika martanin HTTP. Idan abokin ciniki ya karya haɗin, an soke soket ɗin kuma an rufe shi ta amfani da shi .
Nuna aiki akan_recv()
static void on_recv(void *arg, int fd, uint32_t events) {
RequestBuffer *buffer = arg;
// Принимаем входные данные до тех пор, что recv возвратит 0 или ошибку
ssize_t nread;
while ((nread = recv(fd, buffer->data + buffer->size,
REQUEST_BUFFER_CAPACITY - buffer->size, 0)) > 0)
buffer->size += nread;
// Клиент оборвал соединение
if (nread == 0) {
SAFE_CALL(reactor_deregister(reactor, fd), -1);
SAFE_CALL(close(fd), -1);
request_buffer_destroy(buffer);
return;
}
// read вернул ошибку, отличную от ошибки, при которой вызов заблокирует
// поток
if (errno != EAGAIN && errno != EWOULDBLOCK) {
request_buffer_destroy(buffer);
fail("read");
}
// Получен полный HTTP запрос от клиента. Теперь регистрируем обработчика
// событий для отправки данных
if (request_buffer_is_complete(buffer)) {
request_buffer_clear(buffer);
SAFE_CALL(reactor_reregister(reactor, fd, EPOLLOUT, on_send, buffer),
-1);
}
}Mai Gudanar da Taron on_send() da ake kira bayan OS ya haifar da wani taron EPOLLOUT, ma'ana cewa haɗin ya yi rajista on_recv(), shirye don aika bayanai. Wannan aikin yana aika martanin HTTP mai ɗauke da HTML tare da hoto ga abokin ciniki sannan ya canza mai sarrafa taron zuwa on_recv().
Nuna aikin kan_send().
static void on_send(void *arg, int fd, uint32_t events) {
const char *content = "<img "
"src="https://habrastorage.org/webt/oh/wl/23/"
"ohwl23va3b-dioerobq_mbx4xaw.jpeg">";
char response[1024];
sprintf(response,
"HTTP/1.1 200 OK" CRLF "Content-Length: %zd" CRLF "Content-Type: "
"text/html" DOUBLE_CRLF "%s",
strlen(content), content);
SAFE_CALL(send(fd, response, strlen(response), 0), -1);
SAFE_CALL(reactor_reregister(reactor, fd, EPOLLIN, on_recv, arg), -1);
}Kuma a ƙarshe, a cikin fayil ɗin http_server.c, cikin aiki main() Mun ƙirƙiri wani I/O reactor ta amfani da reactor_new(), Ƙirƙiri soket ɗin uwar garken kuma yi rajistar shi, fara reactor ta amfani da reactor_run() daidai minti daya, sa'an nan kuma mu saki albarkatun mu fita shirin.
Nuna http_server.c
#include "reactor.h"
static Reactor *reactor;
#include "common.h"
int main(void) {
SAFE_CALL((reactor = reactor_new()), NULL);
SAFE_CALL(
reactor_register(reactor, new_server(false), EPOLLIN, on_accept, NULL),
-1);
SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
SAFE_CALL(reactor_destroy(reactor), -1);
}Bari mu duba cewa komai yana aiki kamar yadda aka zata. Hadawa (chmod a+x compile.sh && ./compile.sh a cikin tushen aikin) kuma kaddamar da uwar garken da aka rubuta da kansa, bude a cikin browser kuma duba abin da muke tsammani:

Ma'aunin aiki
Nuna ƙayyadaddun motata
$ screenfetch
MMMMMMMMMMMMMMMMMMMMMMMMMmds+. OS: Mint 19.1 tessa
MMm----::-://////////////oymNMd+` Kernel: x86_64 Linux 4.15.0-20-generic
MMd /++ -sNMd: Uptime: 2h 34m
MMNso/` dMM `.::-. .-::.` .hMN: Packages: 2217
ddddMMh dMM :hNMNMNhNMNMNh: `NMm Shell: bash 4.4.20
NMm dMM .NMN/-+MMM+-/NMN` dMM Resolution: 1920x1080
NMm dMM -MMm `MMM dMM. dMM DE: Cinnamon 4.0.10
NMm dMM -MMm `MMM dMM. dMM WM: Muffin
NMm dMM .mmd `mmm yMM. dMM WM Theme: Mint-Y-Dark (Mint-Y)
NMm dMM` ..` ... ydm. dMM GTK Theme: Mint-Y [GTK2/3]
hMM- +MMd/-------...-:sdds dMM Icon Theme: Mint-Y
-NMm- :hNMNNNmdddddddddy/` dMM Font: Noto Sans 9
-dMNs-``-::::-------.`` dMM CPU: Intel Core i7-6700 @ 8x 4GHz [52.0°C]
`/dMNmy+/:-------------:/yMMM GPU: NV136
./ydNMMMMMMMMMMMMMMMMMMMMM RAM: 2544MiB / 7926MiB
.MMMMMMMMMMMMMMMMMMMBari mu auna aikin uwar garken mai zare ɗaya. Bari mu bude tashoshi biyu: a daya za mu gudu ./http_server, a cikin wani daban- . Bayan minti daya, za a nuna ƙididdiga masu zuwa a tasha ta biyu:
$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
8 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 493.52us 76.70us 17.31ms 89.57%
Req/Sec 24.37k 1.81k 29.34k 68.13%
11657769 requests in 1.00m, 1.60GB read
Requests/sec: 193974.70
Transfer/sec: 27.19MBSabar ɗinmu mai zare guda ɗaya ta sami damar aiwatar da buƙatun sama da miliyan 11 a cikin minti ɗaya waɗanda suka samo asali daga haɗin kai 100. Ba mummunan sakamako ba, amma za a iya inganta shi?
Multithreaded uwar garken
Kamar yadda aka ambata a sama, ana iya ƙirƙirar reactor na I/O a cikin zaren daban-daban, ta haka ne ake amfani da duk nau'ikan CPU. Bari mu sanya wannan hanyar a aikace:
Nuna http_server_multithreaded.c
#include "reactor.h"
static Reactor *reactor;
#pragma omp threadprivate(reactor)
#include "common.h"
int main(void) {
#pragma omp parallel
{
SAFE_CALL((reactor = reactor_new()), NULL);
SAFE_CALL(reactor_register(reactor, new_server(true), EPOLLIN,
on_accept, NULL),
-1);
SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
SAFE_CALL(reactor_destroy(reactor), -1);
}
}Yanzu kowane zaren reactor:
static Reactor *reactor;
#pragma omp threadprivate(reactor)Lura cewa hujjar aikin new_server() ni'ima true. Wannan yana nufin cewa mun sanya zaɓi ga soket ɗin uwar garken don amfani da shi a cikin mahalli da yawa. Kuna iya karanta ƙarin bayani .
Gudu na biyu
Yanzu bari mu auna aikin uwar garken mai zaren Multi-threaded:
$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
8 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.14ms 2.53ms 40.73ms 89.98%
Req/Sec 79.98k 18.07k 154.64k 78.65%
38208400 requests in 1.00m, 5.23GB read
Requests/sec: 635876.41
Transfer/sec: 89.14MBYawan buƙatun da aka sarrafa a cikin minti 1 ya ƙaru da ~ 3.28 sau! Amma mun kasance kusan ~ XNUMX miliyan ne kawai na lambar zagaye, don haka bari mu yi ƙoƙarin gyara hakan.
Da farko bari mu dubi kididdigar da aka samar :
$ sudo perf stat -B -e task-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,branches,branch-misses,cache-misses ./http_server_multithreaded
Performance counter stats for './http_server_multithreaded':
242446,314933 task-clock (msec) # 4,000 CPUs utilized
1 813 074 context-switches # 0,007 M/sec
4 689 cpu-migrations # 0,019 K/sec
254 page-faults # 0,001 K/sec
895 324 830 170 cycles # 3,693 GHz
621 378 066 808 instructions # 0,69 insn per cycle
119 926 709 370 branches # 494,653 M/sec
3 227 095 669 branch-misses # 2,69% of all branches
808 664 cache-misses
60,604330670 seconds time elapsed, tari tare da -march=native, , karuwa a yawan hits , karuwa MAX_EVENTS da amfani EPOLLET bai ba da gagarumin karuwa a cikin aikin ba. Amma menene zai faru idan kun ƙara yawan haɗin haɗin gwiwa lokaci guda?
Ƙididdiga don haɗin kai guda 352:
$ wrk -c352 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
8 threads and 352 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.12ms 3.79ms 68.23ms 87.49%
Req/Sec 83.78k 12.69k 169.81k 83.59%
40006142 requests in 1.00m, 5.48GB read
Requests/sec: 665789.26
Transfer/sec: 93.34MBAn sami sakamakon da ake so, kuma tare da shi jadawali mai ban sha'awa yana nuna dogaro da adadin buƙatun da aka sarrafa a cikin minti 1 akan adadin haɗin:

Mun ga cewa bayan ɗaruruwan haɗin haɗin gwiwa, adadin buƙatun da aka sarrafa na sabobin biyu ya ragu sosai (a cikin sigar zaren Multi-threaded wannan ya fi sananne). Wannan yana da alaƙa da aiwatar da tari na Linux TCP/IP? Jin kyauta don rubuta zato game da wannan hali na jadawali da ingantawa don zaɓuɓɓuka masu zare da yawa da guda ɗaya a cikin sharhi.
Yadda a cikin sharhi, wannan gwajin aikin ba ya nuna halayen I / O reactor a ƙarƙashin kaya na gaske, saboda kusan koyaushe uwar garken yana hulɗa tare da bayanan bayanai, fitar da rajistan ayyukan, yana amfani da cryptography tare da da dai sauransu, sakamakon abin da lodi ya zama maras Uniform (dynamic). Za a gudanar da gwaje-gwaje tare da abubuwan ɓangare na uku a cikin labarin game da proactor I/O.
Rashin hasara na I/O reactor
Kuna buƙatar fahimtar cewa I/O reactor ba ya da kura-kurai, wato:
- Yin amfani da reactor na I/O a cikin mahalli da yawa yana da ɗan wahala, saboda dole ne ku sarrafa kwararar ruwa da hannu.
- Aiki ya nuna cewa a mafi yawan lokuta lodi ba Uniform ba ne, wanda zai iya haifar da tsinkayar zaren guda ɗaya yayin da wani ya shagaltu da aiki.
- Idan wani mai gudanar da taron ya toshe zaren, to shi ma mai zaɓin tsarin zai toshe, wanda zai haifar da kurakurai masu wuyar ganowa.
Yana magance waɗannan matsalolin , wanda sau da yawa yana da jadawali wanda ke rarraba kaya daidai gwargwado zuwa tafkin zaren, kuma yana da API mafi dacewa. Za mu yi magana game da shi daga baya, a cikin wani labarin na.
ƙarshe
Anan ne tafiyar mu daga ka'idar kai tsaye zuwa sharar profiler ta zo ƙarshe.
Bai kamata ku tsaya a kan wannan ba, saboda akwai wasu hanyoyi masu ban sha'awa iri ɗaya daidai don rubuta software na cibiyar sadarwa tare da matakai daban-daban na dacewa da sauri. Abin sha'awa, a ganina, ana ba da hanyoyin haɗin gwiwa a ƙasa.
Har sai wani lokaci!
Ayyuka masu ban sha'awa
- Si
Me kuma zan karanta?
source: www.habr.com
