io_uring 異步
要求內(nèi)核linux 5.10
異步四元組:1、init(create)2、commit 3、callback 4、destory
fio : 測(cè)iops一秒鐘讀寫(xiě)磁盤(pán)的次數(shù)
方式 | 磁盤(pán)iops |
---|---|
io_uring | 11.6k |
libaio | 10.7k |
psync | 5k |
spdk(內(nèi)存操作 , 盡可能都放到用戶態(tài)) | 157k |
io_uring 使用
io_uring內(nèi)核api:
io uring. setup();
io uring register();
io_ uring_ enter();
liburing接口:
- io_uring. _queue. init. params
- io_uring_prep_accept
- io_ uring. prep_recv
- io_uring_prep_send(uring, )
- io_ uring_submit0;
- io_uring wait_cqe
- io_uring_ peek_ batch_ cqe
- io_uring_cq_advance//取消事件
猜測(cè)運(yùn)行機(jī)制:
io _uring. _setup();
做兩件事
1)注冊(cè)兩個(gè)隊(duì)列
2)使用mmap映射內(nèi)核的隊(duì)列和用戶態(tài)的隊(duì)列:
echo_websever:
// io_uring, tcp server
// multhread, select/poll, epoll, coroutine, iouring
// reactor
// io
#include <liburing.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define ENTRIES_LENGTH 4096
enum {
READ,
WRITE,
ACCEPT,
};
struct conninfo {
int connfd;
int type;
};
void set_read_event(struct io_uring *ring, int fd, void *buf, size_t len, int flags) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
io_uring_prep_recv(sqe, fd, buf, len, flags);
struct conninfo ci = {
.connfd = fd,
.type = READ
};
memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}
void set_write_event(struct io_uring *ring, int fd, const void *buf, size_t len, int flags) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
io_uring_prep_send(sqe, fd, buf, len, flags);
struct conninfo ci = {
.connfd = fd,
.type = WRITE
};
memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}
void set_accept_event(struct io_uring *ring, int fd,
struct sockaddr *cliaddr, socklen_t *clilen, unsigned flags) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
io_uring_prep_accept(sqe, fd, cliaddr, clilen, flags);
struct conninfo ci = {
.connfd = fd,
.type = ACCEPT
};
memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}
int main() {
int listenfd = socket(AF_INET, SOCK_STREAM, 0); //
if (listenfd == -1) return -1;
// listenfd
struct sockaddr_in servaddr, clientaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9999);
if (-1 == bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) {
return -2;
}
listen(listenfd, 10);
struct io_uring_params params;
memset(¶ms, 0, sizeof(params));
// epoll -->
struct io_uring ring;
io_uring_queue_init_params(ENTRIES_LENGTH, &ring, ¶ms);
socklen_t clilen = sizeof(clientaddr);
set_accept_event(&ring, listenfd, (struct sockaddr*)&clientaddr, &clilen, 0);
char buffer[1024] = {0};
//
while (1) {
struct io_uring_cqe *cqe;//從sqe地址復(fù)制地址
io_uring_submit(&ring) ; //提交,在這個(gè)階段進(jìn)行accpet和recv、write等
int ret = io_uring_wait_cqe(&ring, &cqe); //回調(diào)
struct io_uring_cqe *cqes[10];
int cqecount = io_uring_peek_batch_cqe(&ring, cqes, 10);// 10是每次最多返回10個(gè)隊(duì)列元素
int i = 0;
unsigned count = 0;
for (i = 0;i < cqecount;i ++) {
cqe = cqes[i];
count ++;
struct conninfo ci;
memcpy(&ci, &cqe->user_data, sizeof(ci));
if (ci.type == ACCEPT) {
int connfd = cqe->res;
set_read_event(&ring, connfd, buffer, 1024, 0);
} else if (ci.type == READ) {
int bytes_read = cqe->res;
if (bytes_read == 0) {
close(ci.connfd);
} else if (bytes_read < 0) {
} else {
printf("buffer : %s\n", buffer);
set_write_event(&ring, ci.connfd, buffer, bytes_read, 0);
}
} else if (ci.type == WRITE) {
set_read_event(&ring, ci.connfd, buffer, 1024, 0);
}
}
io_uring_cq_advance(&ring, count);
}
}
對(duì)比于epoll的效果
都采用echo_websever:
epoll: 60w
io_uring: 65w文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-636548.html
io_uring效果好在哪?
epoll是把io放入了紅黑樹(shù)
io_uring共享內(nèi)存:存儲(chǔ)空間、修改變量文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-636548.html
到了這里,關(guān)于io_uring筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!