我們知道,在乙個基於協程的應用程式中,可能會產生數以千記的協程,所有這些協程,會有乙個的排程器來統一排程。
另外我們知道,高效能的程式首要注意的就是避免程式阻塞。那麼,在以協程為最小執行單位的程式中,同樣也需要確保這一點,即每乙個協程都不能發生阻塞。因為只要某乙個協程發生了阻塞,那麼整個排程器就阻塞住了,後續等待的協程得不到執行,整個程式此時也將死翹翹了。那麼,如果需要保證任意乙個協程都不阻塞,該怎麼做呢?
通常,協程主排程器管理著本執行緒中所有的協程,並依次排程這些協程執行,在乙個協程執行完之後,需要將執行許可權交給排程器,即進行 yield 操作,以便排程器能夠排程後續等待執行的協程。如果在某個協程內,含有阻塞操作,如開啟資料庫連線:
exe_non_block1();
open_db_conn(...);
exe_non_block2();
如上邊**所示,先執行了exe_non_block1
, 然後開啟乙個資料庫連線,之後再執行exe_non_block2
, 如果對這段**不做任何處理,倘若開啟資料庫連線需要耗時很多,那麼在這期間,整個程式就阻塞住了,這種情況是絕對不能容許的。怎麼解決呢?
我們看,先執行了exe_non_block2
, 然後執行open_db_conn
, 如果能夠把open_db_conn
這個函式呼叫放到其他的執行緒中去執行,同時本協程yield
,交出執行許可權;之後,當open_db_conn
在其他執行緒執行完畢時,再切換到這個協程,並且能夠接著exe_non_block2
繼續執行,那麼我們就可以解決上邊提出的問題, 保證整個主排程器不會阻塞,即便某乙個協程中需要進行阻塞操作,我們也可以把這段會阻塞的**放到其他執行緒中取執行,等執行完成後,再切換回來。換句話說,就是需要協程有這樣的特性:
能夠按照**順序依次在多個執行緒中執行
那麼,協程有這樣的特性嗎? 很幸運,協程是有的,因為在每次交出執行許可權(即yield
)時,都會保留棧資訊。請看下邊的實驗**(multi_thread_switch.c):
#include "../libcoro/coro.h"
#include #include #include coro_context main_ctx;
coro_context parallel_ctx;
coro_context ctxa;
pthread_mutex_t mutex = pthread_mutex_initializer;
coro_context *current_main_ctx;
void parallel_coro_func(void *arg);
void* thread_main_func(void* arg)
void parallel_coro_func(void *arg)
}void coro_funca(void *arg)
}int main(void)
pthread_t mpid = pthread_self();
printf("main thread:%lu\n", mpid);
while(1)
return 0;
}
-eof- 協程的多執行緒切換
我們知道,在乙個基於協程的應用程式中,可能會產生數以千記的協程,所有這些協程,會有乙個的排程器來統一排程。另外我們知道,高效能的程式首要注意的就是避免程式阻塞。那麼,在以協程為最小執行單位的程式中,同樣也需要確保這一點,即每乙個協程都不能發生阻塞。因為只要某乙個協程發生了阻塞,那麼整個排程器就阻塞住...
多執行緒與協程爬蟲
網路爬蟲是一種高io密集型任務,所以傳統的程序或者多程序並不適合網路爬蟲。雖然由於cpython中全域性直譯器鎖gil的存在,無法真正意義上的實現多執行緒,但這種 不完美的多執行緒 依然可以大大提高爬蟲效率,當然在提高爬蟲效率方面還有大家所熟知的協程。比較官方的介紹我就不說了,畢竟瞅了一眼一大串,這...
多執行緒 多程序 協程
占用的資源 程序 執行緒 協程 程序的顆粒度太大,每次都要有上下的調入,儲存,調出。執行緒 乙個軟體的執行不可能是一條邏輯執行的,必定有多個分支和多個程式段,就好比要實現程式a,實際分成 a,b,c等多個塊組合而成 這裡的a,b,c就是執行緒,也就是說執行緒是共享了程序的上下文環境,的更為細小的cp...