EOS有幾個線程
nodeso節點的工作線程包括:一個主線程,一個信號處理線程和四個線程池。
nodeos(10265 主線程&信號處理線程) : 進行異步io投遞 `epoll_wait` | 接收系統信號並處理
─┬─{nodeos}(10311 controller線程池_1: 異步執行塊block_state創建,塊中交易驗證時的交易解簽名計算)
├─{nodeos}(10312 controller線程池_2)
├─{nodeos}(10314 producer_plugin線程池_1: 異步執行交易解簽名計算)
├─{nodeos}(10315 producer_plugin線程池_2)
├─{nodeos}(10317 http_plugin線程池_1: http服務)
├─{nodeos}(10318 http_plugin線程池_2)
└─{nodeos}(10319 net_plugin線程池_1: p2p服務)
-
主線程:
main
函數啓動線程,該線程執行完程序初始化工作後,會調用app().io_service.run()
, 啓動boost::asio::io_service
的異步io服務,通過異步io方式完成節點塊生產,交易處理等主要業務工作。void application::exec() { boost::asio::io_service::work work(*io_serv); (void)work; bool more = true; while( more || io_serv->run_one() ) { while( io_serv->poll_one() ) {} // execute the highest priority item more = pri_queue.execute_highest(); } shutdown(); /// perform synchronous shutdown io_serv.reset(); }
-
eos中交易不支持並行處理, 不允許在除主線程之外的其它線程中重複執行io_serv.run()操作
boost::asio::io_service& get_io_service() { return *io_serv; } producer_plugin::producer_plugin() : my(new producer_plugin_impl(app().get_io_service())){ // 在構造時傳入 app().get_io_service() my->_self = this; } producer_plugin_impl(boost::asio::io_service& io) :_timer(io)
-
-
信號處理線程:子線程,通過異步io服務,接收系統信號並處理。
boost::asio::io_service startup_thread_ios; //信號處理線程 setup_signal_handling_on_ios(startup_thread_ios); std::thread startup_thread([&startup_thread_ios]() { startup_thread_ios.run(); }); void application::setup_signal_handling_on_ios(boost::asio::io_service& ios, bool startup)
-
線程池,線程池啓動的工作線程數可通過啓動參數配置。 (默認池內2條工作線程)
struct controller_impl { ... boost::asio::thread_pool thread_pool; //線程池 } controller_impl( const controller::config& cfg, controller& s ){ ... thread_pool( cfg.thread_pool_size ) }
-
controller
線程池:異步執行塊block_state
創建,塊中交易驗證時的交易解簽名計算。
執行塊相關操作時,較耗時且與排序無關的動作都會投遞到controller線程池執行。-
塊交易驗證時的解簽名操作 (節點收到塊)
// 節點收到塊,會調用apply_block() 函數執行塊中交易,進行塊驗證 void apply_block( const block_state_ptr& bsp, controller::block_status s ) { ... transaction_metadata::start_recover_keys( mtrx, thread_pool, chain_id, microseconds::maximum() ); } //在線程池`thread_pool`中異步執行解簽名函數,異步解簽名的執行結果,會放入交易的 `signing_keys_future` 中 //真正解簽名算法是 trn.get_signature_keys(),解出的公鑰放到recovered_pub_keys中。 signing_keys_future_type transaction_metadata::start_recover_keys( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds time_limit )
-
塊狀態
block_state
數據創建操作(兩輪共識計算都在這裏完成)
-
-
producer_plugin
線程池:負責異步執行交易解簽名計算。void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options){ ... my->_thread_pool.emplace( thread_pool_size ); }
-
爲接收到的投遞交易進行異步解簽名計算(在節點收到其它節點/客戶端廣播的交易時被調用)
void on_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function<transaction_trace_ptr> next) { signing_keys_future_type future = transaction_metadata::start_recover_keys( trx, _thread_pool->get_executor(), chain.get_chain_id(), fc::microseconds( cfg.max_transaction_cpu_usage ) ); }
-
等待解簽名計算完成,將交易投遞到主線程的異步io服務中處理。
boost::asio::post( *_thread_pool, [self = this, future, trx, persist_until_expired, next]() { if( future.valid() ) future.wait(); app().post(priority::low, [self, trx, persist_until_expired, next]() { self->process_incoming_transaction_async( trx, persist_until_expired, next ); }); });
-
-
http_plugin
線程池: http 的 response 修改成多線程optional<boost::asio::thread_pool> thread_pool
-
net_plugin
線程池optional<boost::asio::thread_pool> thread_pool
-
EOS 異步框架 boost::asio
EOS 異步框架是通過實現一個任務隊列, 然後往隊列中 post 任務來實現, 而消費者不停地從中提取 task 並且執行。
boost::asio
- 它是基於操作系統提供的異步機制( 底層封裝了 select/ epoll/ kqueue/ overlapped, 適用各種操作系統 ),採用前攝器設計模式來實現可移植的異步操作。
- 通過 post 添加任務, run 執行任務。