1. 程式人生 > >boost asio中io_service類的幾種使用

boost asio中io_service類的幾種使用

兩個 響應時間 and 計時 service實例 nec sock 不同 das

io_service類

你應該已經發現大部分使用Boost.Asio編寫的代碼都會使用幾個io_service的實例。io_service是這個庫裏面
最重要的類;它負責和操作系統打交道,等待所有異步操作的結束,然後為每一個異步操作調用其完成處
理程序。
如果你選擇用同步的方式來創建你的應用,你則不需要考慮我將在這一節向你展示的東西。 你有多種不同
的方式來使用io_service。在下面的例子中,我們有3個異步操作,2個socket連接操作和一個計時器等待操
作:
有一個io_service實例和一個處理線程的單線程例子:
io_service service; // 所有socket操作都由service來處理

ip::tcp::socket sock1(service); // all the socket operations are handled by service
ip::tcp::socket sock2(service);

sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
service.run();
有一個io_service實例和多個處理線程的多線程例子:

io_service service;
ip::tcp::socket sock1(service);
ip::tcp::socket sock2(service);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
boost::thread( run_service);
void run_service()
{
service.run();
}
有多個io_service實例和多個處理線程的多線程例子:
io_service service[2];
ip::tcp::socket sock1(service[0]);
ip::tcp::socket sock2(service[1]);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service[0], boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 2; ++i)
boost::thread( boost::bind(run_service, i));

void run_service(int idx)
{
service[idx].run();
}
首先,要註意你不能擁有多個io_service實例卻只有一個線程。下面的代碼片段沒有任何意義:
for ( int i = 0; i < 2; ++i)
service[i].run();
上面的代碼片段沒有意義是因為service[1].run()需要service[0].run()先結束。因此,所有由service[1]處理的
異步操作都需要等待,這顯然不是一個好主意。
在前面的3個方案中,我們在等待3個異步操作結束。為了解釋它們之間的不同點,我們假設:過一會操作1
完成,然後接著操作2完成。同時我們假設每一個完成處理程序需要1秒鐘來完成執行。
在第一個例子中,我們在一個線程中等待三個操作全部完成,第1個操作一完成,我們就調用它的完成處理
程序。盡管操作2緊接著完成了,但是操作2的完成處理程序需要在1秒鐘後,也就是操作1的完成處理程序
完成時才會被調用。
第二個例子,我們在兩個線程中等待3個異步操作結束。當操作1完成時,我們在第1個線程中調用它的完成
處理程序。當操作2完成時,緊接著,我們就在第2個線程中調用它的完成處理程序(當線程1在忙著響應操
作1的處理程序時,線程2空閑著並且可以回應任何新進來的操作)。
在第三個例子中,因為操作1是sock1的connect,操作2是sock2的connect,所以應用程序會表現得像第二
個例子一樣。線程1會處理sock1 connect操作的完成處理程序,線程2會處理sock2的connect操作的完成處
理程序。然而,如果sock1的connect操作是操作1,deadline_timer t的超時操作是操作2,線程1會結束正
在處理的sock1 connect操作的完成處理程序。因而,deadline_timer t的超時操作必須等sock1 connect操
作的完成處理程序結束(等待1秒鐘),因為線程1要處理sock1的連接處理程序和t的超時處理程序。

下面是你需要從前面的例子中學到的:
第一種情況是非常基礎的應用程序。因為是串行的方式,所以當幾個處理程序需要被同時調用時,你
通常會遇到瓶頸。如果一個處理程序需要花費很長的時間來執行,所有隨後的處理程序都不得不等
待。
第二種情況是比較適用的應用程序。他是非常強壯的——如果幾個處理程序被同時調用了(這是有可
能的),它們會在各自的線程裏面被調用。唯一的瓶頸就是所有的處理線程都很忙的同時又有新的處
理程序被調用。然而,這是有快速的解決方式的,增加處理線程的數目即可。
第三種情況是最復雜和最難理解的。你只有在第二種情況不能滿足需求時才使用它。這種情況一般就
是當你有成千上萬實時(socket)連接時。你可以認為每一個處理線程(運行io_service::run()的線
程)有它自己的select/epoll循環;它等待任意一個socket連接,然後等待一個讀寫操作,當它發現這
種操作時,就執行。大部分情況下,你不需要擔心什麽,唯一你需要擔心的就是當你監控的socket數
目以指數級的方式增長時(超過1000個的socket)。在那種情況下,有多個select/epoll循環會增加應
用的響應時間。
如果你覺得你的應用程序可能需要轉換到第三種模式,請確保監聽操作的這段代碼(調用io_service::run()
的代碼)和應用程序其他部分是隔離的,這樣你就可以很輕松地對其進行更改。

boost asio中io_service類的幾種使用