资讯专栏INFORMATION COLUMN

编程语言的变迁

atinosun / 3347人阅读

摘要:本文档试图以一个问题的解决方案为主线,描绘出目前常用技术的变迁及使用。脚本语言兴起随着互联网的发展,编程语言兴起,带动了脚本语言的快速发展如今,脚本语言也可以和好的实现后端逻辑,,前端逐渐走向后端,后端也逐渐靠近前端,技术又开始了新的发展。

引言

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86009.html

相关文章

  • 云时代,程序员将面临分化

    摘要:价值云时代,云计算成为了水电气般的基础设施,必然带来程序员的进一步分化。如果说,云时代的云公司们提供的基础设施和技术服务将是一辆车的发动机,那么面向业务开发的程序员其实提供的就是变速箱。 showImg(https://segmentfault.com/img/remote/1460000006923761?w=1024&h=576); 曾经翻译了一篇文章《现在云战争(真的)开始了》 ...

    LoftySoul 评论0 收藏0
  • Docker 架构私有云机遇和挑战

    摘要:说起,必须要介绍是什么东西,为什么中小企业私有云适合使用。看一下现在的架构图开个玩笑。上面这四点导致我们必须要统一架构,最终把整个业务系统迁移到基于的类似于的私有云的平台。 本文系 ArchSummit 大会 CODING 工程师王振威演讲实录。 showImg(https://dn-coding-net-production-pp.qbox.me/c2f81423-54b9-4a7b...

    bang590 评论0 收藏0
  • 前端框架模式变迁

    摘要:现在在前端的框架都是的模式,还有像和之类的变种独特的单向数据流框架。只要将数据流进行规范,那么原来的模式还是大有可为的。我们可以来看一下,框架的图示从图中,我们可以看到形成了一条到,再到,之后是的,一条单向数据流。 前言 前端框架的变迁,体系架构的完善,使得我们只知道框架,却不明白它背后的道理。我们应该抱着一颗好奇心,在探索框架模式的变迁过程中,体会前人的一些理解和思考 本篇将讲述的是...

    ssshooter 评论0 收藏0
  • TiEye:Region 信息变迁历史可视化工具 | TiDB Hackathon 2018 优秀项

    摘要:本文作者是矛盾螺旋队的成员刘玮,他们的项目在中获得了三等奖。博康负责后端框架以及相应的修改,我负责后端查询,振靖负责前端可视化。次日返回赛场,抽签确定时间,最终为第四个出场。 本文作者是矛盾螺旋队的成员刘玮,他们的项目 TiEye 在 TiDB Hackathon 2018 中获得了三等奖。TiEye 是 Region 信息变迁历史可视化工具,通过 PD记录 Region 的Split...

    sevi_stuo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<