採用libevent寫管道事件通知與broadcast通知的效率對比
阿新 • • 發佈:2019-02-08
我們的系統後臺處理模仿memcached,採用libevent的事件通知實現資料的傳送,採用linux的條件變數實現業務接收處理。因其存在可替換性,故對這兩種方式的效率進行了部分測試。下面貼上部分原始碼:
預測: 因條件變數機制是linux底層做的,而libevent的事件通知則是通過執行緒接收與事件關聯,再通過管道實現資料傳遞。故應該是條件變數更快一點。
1,測試程式碼,傳送資料並寫管道通知或者寫條件變數通知:
static void* test1(void* args) { int i = 1; char buff[1] = {'m'}; for (; i < 100000001; ++i) { pthread_mutex_lock(&mutexQueue); q1.push(i); pthread_mutex_unlock(&mutexQueue); //如採用寫管道,就不採用broadcast,如採用broadcast,就不採用寫管道 if (write(threads->notify_send_fd, buff, 1) != 1) { LOG_ERROR("Write Pipe Failed!"); } //pthread_cond_broadcast(&gCondReadInner); } }
2,libevent事件與管道建立
{ threads = static_cast<LIBEVENT_THREAD*>(calloc(1, sizeof(LIBEVENT_THREAD))); threads->base = event_base_new(); int fds[2] = {-1, -1}; if (pipe(fds)) { LOG_ERROR("Create Pipe Failed!"); return FAILED; } threads->notify_receive_fd = fds[0]; threads->notify_send_fd = fds[1]; //建立事件 threads->notify_event = event_new(threads->base, threads->notify_receive_fd,EV_READ | EV_PERSIST, pipefunc, threads); if (NULL == threads->notify_event) { LOG_ERROR("Create Notify Event Failed!"); return FAILED; } //新增事件 if (-1 == event_add((event*)threads->notify_event, 0)) { LOG_ERROR("Add Notify Event Failed!"); return FAILED; } //準備結束,啟動迴圈執行緒 int iRet = 0; if ((iRet = pthread_create(&threads->thread_id, NULL, CLinkMgr::WorkerLibevent, (void*)threads)) != 0) { LOG_ERROR("Create Thread Failed! -- %d", iRet); return FAILED; } }
3,具體的管道接收執行緒實現
<pre name="code" class="cpp">static void pipefunc(int fd, short which, void* arg) { char buff[1] = {0}; if (read(fd, buff, 1) != 1) { LOG_ERROR("Read Text Failed!"); return; } static int count = 0; int x; pthread_mutex_lock(&mutexQueue); x = q1.front(); q1.pop(); pthread_mutex_unlock(&mutexQueue); count++; if (count == 1) { LOG_ERROR("++++++++++++++++++++++ Count Start"); } else if (count >= 100000000) { LOG_ERROR("++++++++++++++++++++++ Count End!, count = %d", count); } }
4,具體的條件變數讀資料實現
static void* ReadWait(void* args)
{
//設定執行緒對cancel狀態的反應,允許退出執行緒
(void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
//設定執行緒對cancel的執行時機,立即執行
(void)pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
static int count = 0;
while (1)
{
pthread_mutex_lock(&mutexQueue);
while (q1.empty())
{
pthread_cond_wait(&gCondReadInner, &mutexQueue);
}
int x = q1.front();
q1.pop();
pthread_mutex_unlock(&mutexQueue);
if (x == 1)
{
LOG_ERROR("++++++++++++++++++++++ Count Start");
}
else if (x >= 100000000)
{
LOG_ERROR("++++++++++++++++++++++ Count End!, count = %d", x);
}
}
}
5,main函式部分程式碼
//測試執行緒
pthread_t tid;
(void)pthread_create(&tid, NULL, test1, NULL);
/*
//建立wait執行緒讀
pthread_t tid1;
(void)pthread_create(&tid1, NULL, ReadWait, NULL);
//測試執行緒
pthread_t tid;
(void)pthread_create(&tid, NULL, test1, NULL);
*/
//迴圈處理
(void)event_base_dispatch(base);
測試結果
資料量 | libevent管道事件用時 | 條件變數通訊用時 |
---|---|---|
1000萬 | 7-8秒 | 2-3秒 |
1億 | 87秒 | 27秒 |
綜上,條件變數的執行緒間通訊效率是libevent寫管道事件通知的3倍,符合我們的預測條件!!!。
也許這就是為什麼memcached僅採用libevent寫管道進行接收,而傳送呼叫系統的傳送函式的原因吧。
另外,通過該測試,能夠看出來,這兩種都是每秒百萬級別的處理速度,對於當前系統的併發量還不存在瓶頸問題。