弁言
做手艺几年下来,要不断跟着手艺的革新而进修,有时会涌现“只见树木,不见森林”的状况,在项目实战中,单方面的手艺计划可能会由于斟酌不周全而致使后期扩大难题以至激发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(磁盘,收集等)合营的更高效。
题目进化:UserInterface
自从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。另有隐含的音讯行列。
这个音讯驱动模子被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,前端逐步走向后端,后端也逐步接近前端,手艺又最先了新的生长。全栈,下一个进阶的目的。