解释一下同步方法与异步方法以及回调函数的关系。若不想很深入的了解这方面内容,可以记住以下结论:
- 对于同时有同步方法和对应异步方法的函数,我们常用异步方法,用独立线程去处理该函数,提高用户的体验。
- 异步方法由于我们需要等待某种事件的发生(例如当前例子中accept等待有网络进程请求连接),而在发生之后我们也需要针对发生的情况进行一些操作,因此我们使用回调函数,回调函数是指发生事件后进行调用的对应函数,可以在回调函数中写你希望程序运行的一切语句。
首先,我们先思考一下我们平时程序的运行是什么样子的?是不是一段程序从头运行到尾,在不包含选择条件等语句的情况下第一行还没运行完第二行是绝对不会运行的。例如以下的例子:
For (i=1;i<=10000000;i++) ans++;
ans=0;
我们发现,第一行一共要运行10000000而且从整个程序上来看,第一行的运行结果是没有影响的,因为无论得到的是几,在第二行都会被归零。但由于计算机程序是从头到尾依次运行的,所以第一行没运行完第二行是绝对不会运行下去的。
而我们回到之前的问题同步方法和异步方法之间的差异。同步方法其实就是严格按照程序运行规则的方法,例如recv(),我们试想一下,在客户端程序如果客户端希望收到服务器发来的消息而用recv()函数,但用户却不知道什么时候服务器会发消息过来,整个程序就会阻塞在这一句语句,不会运行后面的语句,直到收到服务端的程序。可能几秒钟的等待还可以接受,但如果服务器超过三十四十分钟才有消息发送过来呢?整个程序会卡成未响应一直等着而不运行其他操作,这样可能会把用户逼疯吧。
而异步方法则不同,在运行完这这一语句之后,独立打开一个线程来等待事件的发生,而整个程序是照常运行的,不会卡成无响应状态。而是流畅运行。同时,当事件发生时,异步方法会运行一遍回调函数,运行回调函数则标记着该事件已成立,用上面的例子来说就是已经等到了有网络进程请求连接该服务器。通过在回调函数中展示或进行相应操作既可以“偷偷”完成刚刚本应顺序完成的任务,同时整个程序也不会卡住。下图通过时间与代码执行过程两个维度解释了同步方法与异步方法的差异:
以下也给出一个最简单的例子。我们假设计算一个值,计算这个值可能需要用到三十秒左右,是一个比较难算的值。其中有两种方法,同步方法count()与异步方法BeginCount(). 下面我们看看:
使用同步方法:
Printf(“正在为你计算结果,请稍等”);
Ans=Count(); //等待30s,期间不能做任何其他事情
Print(Ans);
Login(); //录入用户信息,与count()无关。
Printf(“正在为你计算结果,请稍等”);
Ans=Count(); //等待30s,期间不能做任何其他事情
Print(Ans);
Login(); //录入用户信息,与count()无关。
使用异步方法:
'`Printf(“正在为你计算结果,你可以先进行其他操作”);
BeginCount(Countcallback); //运行这一语句本身无需等待。
Login();
Void countcallback(int ans){ //回调函数,ans本身作为回调函数的传参
Printf(“ans”);
}`
以上一段代码是一段异步方法的代码,也就是说调用begincount的过程中本身是不会有太大的时间消耗的,可以马上执行下面的login()操作,而是等待三十秒后会自动调用函数countcallback,而其中的计算结果一般也会以传递参数的方式传递给回调函数,在回调函数中即可根据需要进行一系列的操作,当然最简单就是和上面一样输出答案。这样就大大减少了用户无意义的等待时间,可以让用户有更好的程序使用体验。