Web,知微
细小的事物

知微:Switch与If误区

最新想写一些关于编程细致末梢的文章,叫做知微。看文章需要有一定的逆向基础与汇编知识。如果不会的话,不建议阅读。以免给你灌输了错误的思想,而你无法发现。知微相关的文章不保证正确性,只是对发现或者知识点的一种证明。

大概很久以前,对于switch和if。某视频里面说了一句,switch比if要快。于是这个概念就一直记忆到现在。每次碰到这个问题,我基本上都会告诉别人switch比if快。但是为什么快?怎么快的?估计很大一部分人就不知道了。或者说没有听过它俩谁快的说法,代码的编写更因该关注一些细节。毕竟大的方向,框架,算法逻辑什么的,你不一定会写。小的地方你又不了解。那你只是个Copy+C,Copy+V的选手,也无法进步。

同样的代码有两个版本:release 和 debug。这里拿debug来说,为什么拿debug来说,这有涉及到这两个版本的优化问题。可自行查阅相关编译器、解释器的说明。注意它俩并非是名称上的不同。

来看一下两个判断代码:

switch.png


if.png

然后来看一下汇编代码

debug-switch.png

debug-if.png

汇编代码关键的地方我已经备注了,可以发现if语句是每条都会进行判断,有一定的浪费,而switch通过数组直接会索引到相关的printf语句,是比较快的。

知微:上拉引申的IF

昨天晚上想到一个问题,对于页面的上拉操作,当多次触发上拉动作时如何避免多次请求。于是这样实现了一下。

let i=0
if(i==0)
    up

发现这样可以解决多次上拉问题。看似解决了,不过其中的if判断语句存在一个条件竞争的问题。于是想了一条理由,是由于JavaScript编译执行的逻辑问题,造成的一定延迟,所以没有存在条件竞争。于是我用C++重新写了一个类似的。

#include "windows.h"
int i = 0; 
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
    Sleep(300);
    printf( "3,");
    i = 0;
    return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
    if (i == 0){
        i = 1;
        printf( "0,");
        CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    }
    else
    {
        printf( "1,");
    }
    return 0;
}
  
int _tmain(int argc, _TCHAR* argv[])
{ 
    for (size_t i = 0; i < 1000; i++)
    {
        CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    }
    getchar();
    return 0;
}

于是你会发现它还是很好的解决了上拉的问题。由于C++编译后的opcode接近机器码,所以JavaScript存在的编译执行问题,它不存在。但是它依旧没有多次打印“0”。这里伪造多次是通过线程。让我想到Cpu的问题。Cpu切片和线程执行。从代码来看,它存在竞争问题,但是总和一些外在因素,它规避了问题。想来想去还是没有答案,为什么会规避掉竞态问题。