2019-07-21 Diary

消费

时间 内容 金额
2019-07-20 19:55 衣服 109
2019-07-20 20:23 棋牌室 98
15:39 ETC 充值 1000
19:53 蚂蚁毒饵 39.8

随笔

在整理傅里叶级数, 快速傅里叶变换, 傅里叶矩阵等一系列相关的概念, 等理清了再写.

待办

  • 锻炼 B

2019-07-19 Diary

消费

时间 内容 金额
11:55 中餐 13
13:13 推拿 60
18:22 回南通路上零食 16.2

随笔

今晚混一晚. 公司最近做了地址变更, 现在在解除警示.

背景是刚毕业的时候很荣幸拿到了政府的创业扶持资金, 注册了一个公司. 最近想要注销公司, 但是某个投资公司股东非要先股权变更, 不允许直接注销. 股权变更又因为原来的地址有个工商警示, 所以必须要先工商地址变更再解除警示. 好不容易租了个便宜的地方搞好了地址变更, 但是解警会有人上门检查, 然而我现在又在异地上班.

通过租的地方的老师联系了一个在实地上班的小姑娘, 帮忙应付下上门检查. 祈祷下周能顺利通过吧.

就现在政府这办事方法, 扶持创业就是一笑话. 和政法打交道你才会发现, 钱是没用的, 有人才行!

待办

  • 跑步 (延后 - 2019-07-21)

2019-07-18 Diary

消费

时间 内容 金额
2019-07-17 09:30 早餐 5.9
2019-07-17 12:10 午餐 20
2019-07-17 12:11 奶茶 11
2019-07-17 16:32 工作两周年红包 200
2019-07-17 18:37 晚餐 1
09:32 早餐 5.9
12:29 午餐 12
21:09 夜宵牛奶 0.5

随笔

epoll 比 select 高效的原因还是要从他们的实现上来说.

首先, linux 下文件描述符都可以在其状态就绪 (有新的数据, 可以写入数据等) 时, 执行一个指定的回调函数. select 和 epoll 的实现都是基于这一机制, 区别就在于如何利用这一回调机制.

select

当我们调用 select, 并传入一批文件描述符, 假设当前所有文件描述符都不就绪, select 会在所有这些文件描述符上加上一个回调函数, 然后将当前进程睡眠. 回调函数的功能很简单, 就是唤醒睡眠的进程. 进程唤醒后继续执行, 会轮询检查监控的文件描述符是否就绪, 同时将文件描述符上对应的回调函数移除.

epoll

和 select 不同的地方是, epoll 不需要频繁的在监控的文件描述符上添加移除回调函数. 只有当你调用 epoll_ctl 添加监控的文件描述符时 epoll 才会在对应的文件描述符上添加一个回调函数. 相应的, 调用 epoll_ctl 删除监控的文件描述符时会将回调函数移除. 另外需要说明的是, 调用 epoll_create 的时候, epoll 会创建一个文件描述符, 当你调用 epoll_wait 的时候, 会在 epoll 创建的文件描述符上插入一个回调函数, 然后将当前进程睡眠.

epoll 插入到监控的文件描述符上的回调函数所做的事情是, 将当前就绪的文件描述符放到 epoll 自己维护的一个红黑树里, 同时执行 epoll 自己创建的文件描述符上的回调函数, 这个回调函数会将睡眠的进程唤醒. 唤醒的进程会继续执行 epoll_wait 函数, 将之前插入的回调函数移除.

总结

可以发现, epoll 比 select 高效的原因是, a) 不需要频繁的在监控的文件描述符上添加移除回调函数 b) 可以直接获取就绪的文件描述符, 不需要遍历检查每个文件描述符

等待队列

上面的 select 和 epoll 的实现都基于文件描述符在就绪时执行回调函数, 那么这个又是怎么实现的呢?

其实也很简单, 每个文件描述符维护了一个等待队列 (wait_queue_head). 所有的文件描述符都对外暴露一个 file_operations 的结构体 (具体实现是各个 IO 设备的驱动实现的), 其中有一个 poll 方法 (和系统调用 poll 不是同一个东西). 调用这个 poll 方法, 会在等待队列中插入一个等待队列项 (wait_queue), 等待队列项中就有我们要执行的回调函数. 这样当对应的文件描述符状态改变 (写入, 读取等操作) 时就会遍历等待队列并执行相应的回调函数.

其他

用惯了高层语言, 看 select 和 epoll 的源码的时候, 总是会带入一些已经抽象过的概念, 比如进程. 对于内核代码来说, 进程不过就是内存中的一块数据而已, 所有的进程调度, 都是需要内核代码自己实现.

很久不用 c 了, 对 c 的很多语法都忘了. 比如一开始好奇 epoll 的回调函数里怎么拿到对应的文件描述符的, 后来发现原来是因为 wait_queue 是属于一个结构体的, 回调函数中直接基于偏移获取 wait_queue 所属的结构体, 再获取结构体中的文件描述符, 这个不就是闭包的底层实现嘛!

看源码的时候总是看了后面忘前面, 后来发现还是要把代码图形化, 画 UML 图是个好方法. 所以记忆还是要基于图形化!

源码解读Linux等待队列

源码解读poll/select内核机制

源码解读epoll内核机制

待办

  • 锻炼 B (取消)

2019-07-16 Diary

消费

时间 内容 金额
10:38 李雪妮红包 (公司地址解警) 50
12:21 中餐 16
18:31 午餐 5

随笔

在看 linux selectepoll 的底层实现区别, 虽然概念上有点清晰了, 不过感觉还没抓住要点.

待办

  • 锻炼 A (延后 - 20190718)

2019-07-15 Diary

消费

时间 内容 金额
12:17 中餐 13
12:47 雪糕 3.1

随笔

自我归因, 自我说服, 自我辩解这三者能够对我们的思维, 情感和行为进行塑造. 核心的影响者是自我 (内化了的关于自己的概念), 而不是由外部说服者所引发的改变.

归因

我们有一种相信自己能够控制所处环境的基本需要. 为了能够预测和控制发生在我们身上的事情, 我们试图理解人们行为的原因. 另外, 我们对他人的理解自然会影响到我们对他们的行为.

  • 特质归因 (内部归因)

    把所观察到行为的原因归结于个体内部

  • 情境归因 (外部归因

    把社会与物理环境中的某些因素看作是导致个体以某一特定方式行动的原因.

情境引发的行为能对我们的态度和自我意象产生影响的一个主要原因是, 情境的力量是如此庞大, 但看上去却又是如此微不足道.

待办

  • 锻炼 B (已完成)