异步请求池

一.同步与异步

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等下去,直到收到返回信息才继续执行下去。
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有信息返回时系统会通知进程进行处理,这样可以提高执行的效率。
在这里插入图片描述

二.异步请求池实现的架构

异步请求池不管是mysql请求池,redis请求池还是DNS请求池,只要遵循**“零声学院”**的king式四元组,就能按部就班实现出来,下面介绍一下king式四元组。
所谓的king式四元组,只得就是实现异步请求的四个api。

1.commit: 提交请求,主要包括以下功能。

(1)建立网络连接
 (2)组织好对应的协议
 (3)发到对应的服务器
 (4)fd是否可读,fd加入epoll

struct dns_item {
	char *domain;
	char *ip;
};

typedef void (*async_result_cb) (struct dns_item *list, int count)

struct async_context {
	int epfd;
};

struct ep_arg {
	int sockfd;
	
};
//客户端提交请求,这里的domain域是指提交的时DNS请求
int async_client_commit(const char *domain) {
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd < 0) {
		perror("create socket failed\n");
		exit(-1);
	}
	struct sockaddr_in dest;
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	dest.sin_port = htons(53);
	dest.sin_addr.s_addr = inet_addr(DNS_SVR);

	int ret = connect(sockfd, (struct sockaddr *)&dest, sizeof(dest));
	
	/*创建DNS协议,具体协议请网上查找*/
	struct dns_header header = {0};
	dns_create_header(&header);

	struct dns_question question = {0};
	dns_create_question(&question, domain);
	
	/*发到对应的服务器上去*/
	char request[1024] = {0};
	int req_len = dns_build_request(&header, &question, request);
	int slen = sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, (socklen_t*)*addr_len);
	struct ep_arg *eparg = (struct ep_arg *)calloc(1, sizeof(struct ep_arg));
	if(ep_arg == NULL) {
		return -1;
	}
	eparg=>sockfd = sockfd;
	eparg->cb = cb;
	//加入到epool中
	struct epoll_event ev;
	ev.data.ptr = eparg;
	ev.events = EPOLLIN;
	ret = epoll_ctl(ctx->epfd, EPOLL_CTL_ADD, sockfd, &ev)
	return ret;	

2.init:初始化,主要执行异步操作的上下文

(1)创建epoll
(2) 创建 线程,里面用epoll_wait

#define ASYNC_CLIENT_NUM 1024
struct async_context *async_client_init(void) {
	int epfd = epoll_create(1);
	if (epfd < 0) return NULL;

	struct async_context *ctx = calloc(1, sizeof(struct async_context));
	if(ctx == NULL) {
		close(epfd);
		return NULL;
	}
	ctx->epfd = epfd;
	
	pthread_t thread_id;
	int ret = pthread_create(&pthread_id, NULL, dns_async_client_proc, ctx);
	if(ret){
		perror("pthread_create");
		return NULL;
	}
	usleep(1);
	return ctx;
}

static void* dns_async_client_proc(void *arg) {
	struct async_context *ctx = (struct async_context*)arg;
	int epfs = ctx->epfd;

	while(1){
		struct epoll_evet event[ASYNC_CLIENT_NUM] = {0};
		int nready = epoll_wait(epfd, events, ASYNC_CLIENT_NUM, -1);
		if(nready < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			} else {
				break;
			}
		} else if (nready == 0) {
			continue;
		}
		int i = 0;
		for (; i < nready; i++) {
			struct ep_arg* data = (struct ep_arg*)events[i].data.ptr;
			int sockfd = data->sockfd;

			char buffer[1024] = 0;
			struct sockaddr_in addr;
			size_t addr_len = sizeof(struct sockaddr_in);
			int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
			struct dns_item *domain_list = NULL;
			int count = dns_parse_response(buffer, &domain_list);

			data->cb(domain_list, count); //call cb
			int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
			//printf("epoll_ctl DEL --> sockfd:%d\n", sockfd);
			close(sockfd); /
			dns_async_client_free_domains(domain_list, count);
			free(data);
		}
	}

}

3.callback:回调函数,收到数据最处理

static void dns_async_client_result_callback(struct dns_item *list, int count) {
	int i = 0;


	for (i = 0;i < count;i ++) {
		printf("name:%s, ip:%s\n", list[i].domain, list[i].ip);
	}
}

4.destory:销毁请求池
(1)调用close关闭epfd
(2) pthread_cancel取消线程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
异步请求的基本实现方法如下: 1. 基于事件驱动模型(Event-Driven Model)开发异步请求,在此模型下应用程序的各个模块可以根据需求注册监听相应的事件,当事件发生时就会触发对应的回调函数。 2. 设定异步请求的工作流程:先将待处理的请求放入请求队列中,然后从队列中取出一个异步请求并处理,同时保证其他请求还能进入到队列里面等待处理。 3. 建立一个线程或使用协程(Coroutine)来处理异步任务,可以并发地读取和处理请求队列中的请求,提高后台处理请求的效率。 4. 利用回调函数机制,将异步请求处理结果通知给应用程序,类似于Signal/Slot机制,这样在请求处理结束后,回调函数会通知对应的应用程序。 5. 为了防止请求过多,需要对请求队列长度和工作线程数等参数进行合理的调整和控制。 以下是一个基本的异步请求实现的代码示例: ``` #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define MAXQUEUE 1000 #define MAXTHREADS 50 typedef struct { void (*function)(void *arg); void *argument; } task; task queue[MAXQUEUE]; int queueSize = 0; int queueStart = 0; int queueEnd = -1; pthread_mutex_t queueMutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t queueNotEmpty = PTHREAD_COND_INITIALIZER; pthread_cond_t queueNotFull = PTHREAD_COND_INITIALIZER; void enqueue(task t) { pthread_mutex_lock(&queueMutex); while (queueSize >= MAXQUEUE) { pthread_cond_wait(&queueNotFull, &queueMutex); } queueEnd = (queueEnd + 1) % MAXQUEUE; queue[queueEnd] = t; queueSize++; pthread_cond_signal(&queueNotEmpty); pthread_mutex_unlock(&queueMutex); } task dequeue() { task t; pthread_mutex_lock(&queueMutex); while (queueSize <= 0) { pthread_cond_wait(&queueNotEmpty, &queueMutex); } t = queue[queueStart]; queueStart = (queueStart + 1) % MAXQUEUE; queueSize--; pthread_cond_signal(&queueNotFull); pthread_mutex_unlock(&queueMutex); return t; } void *worker(void *arg) { while (1) { task t = dequeue(); t.function(t.argument); } } void createThreadPool(int numThreads) { pthread_t thread[numThreads]; for (int i = 0; i < numThreads; i++) { pthread_create(&thread[i], NULL, &worker, NULL); } } void asyncFunction(void *arg) { int num = *(int *) arg; printf("Async function %d\n", num); } int main() { int numTasks = 100; int threads = 10; createThreadPool(threads); for (int i = 0; i < numTasks; i++) { int *n = (int *) malloc(sizeof(int)); *n = i; task t = {asyncFunction, n}; enqueue(t); } pthread_exit(NULL); } ``` 在此代码中,函数enqueue()和dequeue()实现了异步请求的基本工作流程,createThreadPool()创建了线程以实现异步处理请求,而在main()中,任务被创建并放入异步请求中等待处理。同时,在异步函数asyncFunction()中模拟了异步处理请求的过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值