Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于WFComplexClientTask::dispatch()疑惑 #800

Closed
littledoglily opened this issue Mar 14, 2022 · 13 comments
Closed

关于WFComplexClientTask::dispatch()疑惑 #800

littledoglily opened this issue Mar 14, 2022 · 13 comments

Comments

@littledoglily
Copy link

先说下我对这块逻辑的理解:
client发送数据到server,state为WFT_STATE_UNDEFINED,route_result_.request_object为null, 通过route函数创建一个route task,route task里面执行的结果应该是后续给连接池获取连接用的。
我的问题是:series_of(this)->push_front(this); 这里为什么又要把complex client task放到series里面?再subtask_done里面会不会造成死循环啊?
求解答一下

@Barenboim
Copy link
Contributor

不会的。在router_callback里,一定会改变this任务的状态:

template<class REQ, class RESP, typename CTX>
void WFComplexClientTask<REQ, RESP, CTX>::router_callback(WFRouterTask *task)
{
	this->state = task->get_state();
	if (this->state == WFT_STATE_SUCCESS)
		route_result_ = std::move(*task->get_result());
	else if (this->state == WFT_STATE_UNDEFINED)
	{
		/* should not happend */
		this->state = WFT_STATE_SYS_ERROR;
		this->error = ENOSYS;
	}
	else
		this->error = task->get_error();
}

所以this任务重新被dispatch时,要么执行Client Task的dispatch,要么直接结束,而不会再次产生router task。

@Barenboim
Copy link
Contributor

另外router task是一个路由任务,和连接池没有关系。作用是通过URL实时产生一个或一组IP地址作为client任务的通信目标。

@littledoglily
Copy link
Author

另外router task是一个路由任务,和连接池没有关系。作用是通过URL实时产生一个或一组IP地址作为client任务的通信目标。

为什么在把rout_task插入到当前series前 还要再次把当前的client task插入进来?
series_of(this)->push_front(this); //这一步没理解
series_of(this)->push_front(router_task_);

@Barenboim
Copy link
Contributor

因为此时this任务已经从队列里拿掉了,需要重新push回去,才能被再次dispatch。

@littledoglily
Copy link
Author

因为此时this任务已经从队列里拿掉了,需要重新push回去,才能被再次dispatch。

还有个问题请教一下,连接池里如果当前没有连接可用,通过launch_conn申请的entry 直接放到epoll管理了 没有用来处理当前client的请求的数据发送吗? 扔到epoll监听的EPOLLOUT 事件,这个时候好像没有把对应的entry list放到target idle list里面,那如何触发epollout事件的呢? 代码里没有找到关于处理新entry 在发送的时候添加到target里的地方,是不是我理解的有问题?

@Barenboim
Copy link
Contributor

因为此时this任务已经从队列里拿掉了,需要重新push回去,才能被再次dispatch。

还有个问题请教一下,连接池里如果当前没有连接可用,通过launch_conn申请的entry 直接放到epoll管理了 没有用来处理当前client的请求的数据发送吗? 扔到epoll监听的EPOLLOUT 事件,这个时候好像没有把对应的entry list放到target idle list里面,那如何触发epollout事件的呢? 代码里没有找到关于处理新entry 在发送的时候添加到target里的地方,是不是我理解的有问题?

交给epoll管理是用来等待连接建立完成。之后在handle_connect_result里(此时fd已经从epoll里出来了),会进行数据的发送,发送完成再把fd放入epoll等待读事件。对client session来讲,idle list是那些可复用连接,至少执行完一次request之后,才会把连接放入idle list。

@Barenboim
Copy link
Contributor

项目对你有帮助的话,记得帮我们star一下呀。

@littledoglily
Copy link
Author

项目对你有帮助的话,记得帮我们star一下呀。

Done, 帮助很大, 谢谢解答!

@Barenboim
Copy link
Contributor

感谢使用!

@littledoglily
Copy link
Author

想请教一个和workflow无关的问题:epoll监听的事件应该和socket本身是收数据还是发数据无关吧?
client->server时从连接池拿出来的空连接应该还在监听epollin事件,如果可以一次同步发送成功,那么没有改变epoll监听的事件(epollin),只有一次发送不成功才会修改成epollout状态。

@Barenboim
Copy link
Contributor

Barenboim commented Mar 18, 2022

想请教一个和workflow无关的问题:epoll监听的事件应该和socket本身是收数据还是发数据无关吧?
client->server时从连接池拿出来的空连接应该还在监听epollin事件,如果可以一次同步发送成功,那么没有改变epoll监听的事件(epollin),只有一次发送不成功才会修改成epollout状态。

对的,无论是client还是server,fd长期都保持IN状态。需要写数据时,先同步的写,如果数据可以全部写入tcp buffer,则无需改变fd的状态;如果数据无法全部写入,通过epoll的MOD,原子性的把fd从IN状态改为OUT状态开始异步发送。异步发送完成(fd会从epoll里删除),再把fd以IN状态重新加入epoll。

@littledoglily
Copy link
Author

根据这个issue中的问题 #297, 这种"单工模式" 对并发度和latency 有很大影响吗?

@Barenboim
Copy link
Contributor

不会,比任何所谓全双工都要快。因为大多数情况下,没有必要进行异步写。操作系统会动态调整TCP send buffer的大小,从100多K逐渐增加至少10M。需要异步写的场景很少,所以epoll里的fd基本不用动。如果真的需要异步写,我们的模式也是最快的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants