Windows,软件应用
Windows 编程

redis 死循环为什么CPU很低?

redis的事件循环代码

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

让我不理解的是,这是一个死循环,但是CPU占用很低。所以就看看代码学习一下。由于我只需要时间事件(processTimeEvents)。所以我将aeProcessEvents删掉了一些代码,只保留时间事件。然后CPU暴增。

微信图片_20190918182652.png

可以看到CPU从0.0涨到了90.3于是往上回溯代码。最终发现其中一个比较关键的:aeApiPoll函数。

网上有一段话:aeProcessEvents 都会先 计算最近的时间事件发生所需要等待的时间 ,然后调用 aeApiPoll 方法在这段时间中等待事件的发生,在这段时间中如果发生了文件事件,就会优先处理文件事件,否则就会一直等待,直到最近的时间事件需要触发。跟进去会发现是一个select,它是用来等待文件描述词(普通文件、终端、伪终端、管道、FIFO、套接字及其他类型的字符型)这些的改变事件。

在传递的时候会将tvp传入进来,tvp是最近发生的时间,也被设置成了select的过期时间,所以如果没有发生文件事件,然后又select又过期了,自动会走如下代码

    if (retval > 0) {
        for (j = 0; j <= eventLoop->maxfd; j++) {
            int mask = 0;
            aeFileEvent *fe = &eventLoop->events[j];
            if (fe->mask == AE_NONE) continue;
            if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds))
                mask |= AE_READABLE;
            if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds))
                mask |= AE_WRITABLE;
            eventLoop->fired[numevents].fd = j;
            eventLoop->fired[numevents].mask = mask;
            numevents++;
        }
    }

所以这里的等待就会造成while的一些时间片的释放,然后会降低CPU。

知微: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语句,是比较快的。

[跨平台] 后台定时推送

源码

https://github.com/iwonmo/PushScript

运行方法

参考:https://www.iwonmo.com/archives/1575.html

【如和本页内容存在冲突以本页为准】

数据格式

{"key":"11981af0-980e-476d-956d-3c85937073fe","data":"NB13d5pRHE0JGA1","time":1563636668748,"utime":120000,"type":"uptime"}

key:存储标识

data:存储数据

time:过期时间

utime:更新时间 推送消息后,下次推送时间 = 当前时间 + 更新时间

type:消息类型

none:过期推送删除 

uptime:推送后更新推送时间持续推送

del:删除对应Key

注:格式为JSON,时间为毫秒。 

添加数据

        String _string = "abcd";
        try {
            JsonObject jsonObject = (JsonObject) new JsonObject();
            jsonObject.addProperty("key", UUID.randomUUID().toString());
            jsonObject.addProperty("data", generateString(new Random(), SOURCES, 15));
            jsonObject.addProperty("time", System.currentTimeMillis() + 10000);
            jsonObject.addProperty("utime", 120000);
            jsonObject.addProperty("type", "uptime");
            _string = (jsonObject.toString());
        } catch (Exception e) {
        }
        //创建Socket对象 并写入IP地址及端口号
        Socket socket = new Socket("127.0.0.1", 1992);
        OutputStream ops = socket.getOutputStream();
        OutputStreamWriter opsw = new OutputStreamWriter(ops);
        BufferedWriter bw = new BufferedWriter(opsw);
        bw.write(_string);
        bw.flush();
        bw.close();
        opsw.close();
        ops.close();
        socket.close();

解释

dataDir

数据库存储目录,每次程序运行会自动读取最新的一个库,每隔相应时间会自动保存一份。以防程序崩溃造成数据损失。

http文件

接口回调地址填写文件,将回调地址填写到里面,程序会自动读取。

回调参数

程序到设定日期后会将key、data和type推送给回调地址。获取方式HTTP GET方式获取。

端口

【1992】将JSON数据提交到此端口即可

【1993】程序内部逻辑使用端口不用理会