坚持一个原则:one loop--->one thread---->one io_watcher
事件优先级:timer > io > idle
EventLoop
源码位置:evpp
。EventLoop
是C++版本的loop,对常用的loop功能进行基本封装,主要包括loop的状态、定时器、runInLoop
等单线程模型的事件封装。稍后分析的TimerThread、TcpClient、TcpServer、UdpClient、UdpServer
均是基于EventLoop
实现的。
源码:EventLoop.h
//部分源码分析,Status 作为基类主要用作状态管理
class EventLoop : public Status {
//run内部设置状态为kRunning,然后调用hloop_run进行阻塞调用
//为了不阻塞主线程,应该单单独起线程运行run
// @brief Run loop forever
void run() {
if (loop_ == NULL) return;
if (status() == kRunning) return;
ThreadLocalStorage::set(ThreadLocalStorage::EVENT_LOOP, this);
setStatus(kRunning);
hloop_run(loop_);
setStatus(kStopped);
}
}
//判断是否在当前run的线程
bool isInLoopThread() {
if (loop_ == NULL) return false;
return hv_gettid() == hloop_tid(loop_);
}
// 通过前面的源码分析,loop必须遵守单线程模式,如果需要在其他线程调用需要通过custom event来处理
// 事件,即postEvent。 runInLoop对postEvent进行了封装,支持多线程调用。
// 线程安全
void runInLoop(Functor fn) {
if (isRunning() && isInLoopThread()) {
if (fn) fn();
} else {
queueInLoop(std::move(fn));
}
}
EventLoop总结:
- 需要单独起线程,运行run。否则会阻塞当前线程
- runInLoop封装了postEvent,支持多线程模式
setTimer非线程安全
(易误用)。外部应该调用:setTimerInLoop
源码:EventLoopThread.h
//部分源码,对EventLoop进一步封装,简化调用方式,run内部起线程
class EventLoopThread : public Status {
// @param wait_thread_started: if ture this method will block until loop_thread started.
// @param pre: This functor will be executed when loop_thread started.
// @param post:This Functor will be executed when loop_thread stopped.
void start(bool wait_thread_started = true,
Functor pre = Functor(),
Functor post = Functor()) {
if (status() >= kStarting && status() < kStopped) return;
setStatus(kStarting);
//内部启线程,方便外部调用
thread_ = std::make_shared<std::thread>(&EventLoopThread::loop_thread, this, pre, post);
if (wait_thread_started) {
while (loop_->status() < kRunning) {
hv_delay(1);
}
}
}
private:
EventLoopPtr loop_;
std::shared_ptr<std::thread> thread_;//内部loop工作线程
}
EventLoopThread总结:
1.使用简单,start即可,不会阻塞当前线程
2. EventLoopThread 属于单线程模式,性能不及高并发
源码:EventLoopThreadPool.h
class EventLoopThreadPool : public Status {
//负载均衡模型,根据不同的负责模型,返回合适的EventLoop
EventLoopPtr nextLoop(load_balance_e lb = LB_RoundRobin) {
size_t numLoops = loop_threads_.size();
if (numLoops == 0) return NULL;
size_t idx = 0;
if (lb == LB_RoundRobin) {
if (++next_loop_idx_ >= numLoops) next_loop_idx_ = 0;
idx = next_loop_idx_ % numLoops;
} else if (lb == LB_Random) {
idx = hv_rand(0, numLoops - 1);
} else if (lb == LB_LeastConnections) {
for (size_t i = 1; i < numLoops; ++i) {
if (loop_threads_[i]->loop()->connectionNum < loop_threads_[idx]->loop()->connectionNum) {
idx = i;
}
}
} else {
// Not Implemented
}
return loop_threads_[idx]->loop();
}
//根据下标获取EventLoop,如果不指定则通过负载均衡模型来动态选择EventLoop
EventLoopPtr loop(int idx = -1) {
if (idx >= 0 && idx < (int)loop_threads_.size()) {
return loop_threads_[idx]->loop();
}
return nextLoop();
}
//启动指定数量的EventLoopThread,实现多线程模型
void start(bool wait_threads_started = false,
std::function<void(const EventLoopPtr&)> pre = NULL,
std::function<void(const EventLoopPtr&)> post = NULL) {
if (thread_num_ == 0) return;
if (status() >= kStarting && status() < kStopped) return;
setStatus(kStarting);
auto started_cnt = std::make_shared<std::atomic<int>>(0);
auto exited_cnt = std::make_shared<std::atomic<int>>(0);
loop_threads_.clear();
for (int i = 0; i < thread_num_; ++i) {
auto loop_thread = std::make_shared<EventLoopThread>();
const EventLoopPtr& loop = loop_thread->loop();
loop_thread->start(false,
[this, started_cnt, pre, &loop]() {
if (++(*started_cnt) == thread_num_) {
setStatus(kRunning);
}
if (pre) pre(loop);
return 0;
},
[this, exited_cnt, post, &loop]() {
if (post) post(loop);
if (++(*exited_cnt) == thread_num_) {
setStatus(kStopped);
}
return 0;
}
);
loop_threads_.push_back(loop_thread);
}
if (wait_threads_started) {
while (status() < kRunning) {
hv_delay(1);
}
}
}
private:
int thread_num_;//工作线程数量
std::vector<EventLoopThreadPtr> loop_threads_;//EventLoopThread数组
std::atomic<unsigned int> next_loop_idx_;//负载均衡
}
EventLoopThreadPool总结:
1.使用简单,支持多线程,支持高并发,支持负载均衡