作技術幾年下來,要不停跟着技術的變革而學習,有時會出現「只見樹木,不見森林」的狀況,在項目實戰中,片面的技術方案可能會由於考慮不全面而致使後期擴展困難甚至引起bug。本文檔試圖以一個問題的解決方案爲主線,描繪出目前經常使用技術的變遷及使用。前端
剛學編程的時候,試圖寫一個下載程序:給定一個URL網址,下載並保存爲文件。
基本的C語言知識,加上網上找的資料,就能夠完成這個功能。程序員
std::string DownloadFile(const std::string& url) { // Download code:use while ... } bool SaveFile(const std::string& fileName, const std::string& content) { // Save file code:check success ... } int main(int argc, char* argv[]) { std::string url = argv[1]; std::string content = DownloadFile(url); SaveFile(content); return 0; }
這個是我上學時寫的程序,如今看起來有不少問題(都有什麼問題?),不過基本的功能算是實現了。若是能把裏面的string全換成char*來實現,說明C語言考試能過。編程
這個程序體現了結構化程序編程的特色:順序,循環,分支以及函數。後端
可是實際工做中不可能如此簡單,好比能不能同時下載多個文件,或者將一個文件分片下載?(Flashget,迅雷)
這就引入了多線程:網絡
void DownloadThread(void* param) { if (param) { std::string url = (const char*)param; SaveFile(DownloadFile(url)); DestroySemaphore(); } } int main(int argc, char* argv[]) { std::string urllist = argv[1]; std::vector ulist = ParseUrlList(urllist); for (auto it = ulist.begin(); it != ulist.end(); it++) { int pThread = CreateThread(DownloadThread, it->str()); int pSem = CreateSemaphore(); InitSemaphore(pSem); // save thread context and init sem ... } // 線程同步 WaitAllSemaphore(); return 0; }
到這裏還遠沒有結束,好比如何控制併發的線程數量,若是讓多個下載線程寫入同一個文件(線程互斥?),甚至是多進程的配合等。
這個例子中,問題演變爲如何讓CPU同時作更多的工做?這實際上是技術演變的一個主線,如何讓高速的CPU和低速的IO(磁盤,網絡等)配合的更高效。多線程
自從Windows系統出來後,客戶端編程不再像前面那樣簡單直接了。
總要給用戶一個東西,讓他們點吧,而咱們的程序不可能本身去處理全部屏幕的點擊事件,來判斷用戶到底點了哪一個pixcel,它又屬於哪個button。這些經過和操做系統配合,應用程序能很好的完成。併發
咱們想給下載工具寫一個界面,好比作一個PC版的,讓它能在電腦上跑起來,就像迅雷同樣。編程語言
LRESULT CALLBACK WndProc( //WndProc名稱可自由定義 HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_CREATE: OnCreate(); break; case WM_CLOSE: OnClose(); break; case WM_DOWNLOAD: // 能夠自定義消息 OnDownload(wParam, lParam); break; case WM_STOP_DOWNLOAD: OnStopDownload(); break; case WM_DOWNLOAD_PROGRESS: OnDownloadProgress(); break; // 此處還有各類消息 ... case WM_QUIT: PostQuitMessage(0); // 通知該線程的GetMessage,能夠退出了; break; default: DefWndProc(hwnd, uMsg, wParam, lParam); } return 0; } int main(int argc, char* argv[]) { WNDCLASS wndClass = {}; wndClass.style = WS_WINDOW; wndClass.hIcon = HICON_NONE; ... // 大約1x個參數 wndClass.lpfnWndProc = WndProc; RegisterClass(wndClass); HWND hWnd = CreateWindow(wndClass, ...); ShowWindow(hWnd, SW_SHOW); MSG msg = {}; while (GetMessage(&msg)) // 這裏面有一個WaitSemaphore { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
上例中引入了一個重要的概念Callback,意思就是你等着,我來調你。
同一個應用,不單單是咱們的程序來完成功能,和須要和系統配合。鏈接系統和咱們程序的,在這裏就是Callback和MSG。還有隱含的消息隊列。ide
這個消息驅動模型被Windows發明出來後,一直用到今天。函數
固然,Windows程序這樣的寫法太土了,WndProc裏面的switch誇張的分支能有上千個分支,(Windows的資源管理代碼中,分支就上千個)。
因而乎,各類Framework就跳出來解救廣大程序員了,什麼MFC,ATL、WTL之類。
好比ATL
CApp theApp; int Run() { CMessageLoop loop; theApp.AddMessageLoop(loop); CMainWindow wnd; wnd.Create(); wnd.ShowWindow(); loop.Run(); theApp.RemoveMessageLoop(); } int main(int argc, char* argv[]) { theApp.Init(); int nRet = Run(); theApp.term(); return 0; }
在CMainWindow的實現裏面,多是這樣的:
class CMainWindow: public CWindow { // message map void OnCreate(); void OnClose(); void OnHandler(); //.... }
其它的系統,也隱藏了窗口建立等細節,在系統層面,就封裝好了,方便程序員使用。
好比Android:
public class MyWindow extends Activity { private Handler mMainHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case XXX: onXXX(); break; default: break; } } } protected void onCreate(Bundle savedInstanceState) { // } protected void onDestroy() { // } }
Android中的Handler,其實就是一個消息處理機制(類比WndProc)。咱們須要理解消息,消息隊列及消息處理。
在IOS中,消息隊列別隱藏起來,取而代之的是Delegate模式:
int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([NetChatApp class])); } }
UIApplicationMain中,就維護了消息隊列(Run Loop),檢測應用的生命週期,並經過Delegate分發處理。
隨着互聯網的發展,Web編程語言興起,帶動了腳本語言的快速發展;現在,腳本語言也能夠和好的實現後端邏輯,Nodejs,前端逐漸走向後端,後端也逐漸靠近前端,技術又開始了新的發展。全棧,下一個進階的目標。