作技术几年下来,要不停跟着技术的变革而学习,有时会出现“只见树木,不见森林”的状况,在项目实战中,片面的技术方案可能会由于考虑不全面而致使后期扩展困难甚至引起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,前端逐渐走向后端,后端也逐渐靠近前端,技术又开始了新的发展。全栈,下一个进阶的目标。