forked from wolverinn/Waking-Up
-
Notifications
You must be signed in to change notification settings - Fork 0
/
2023.7.17_作业帮笔试.readme
67 lines (62 loc) · 4.34 KB
/
2023.7.17_作业帮笔试.readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
## epoll及延申
epoll 的三个函数:epoll_create, epoll_ctl, epoll_wait
- 阻塞IO指进程发起调用后会被阻塞,若调用一直不返回则进程一直被挂起,因此,使用阻塞IO时需使用多线程处理多个文件描述符
- 非阻塞IO会立刻返回文件描述符是否就绪,可以在一个线程里轮询多个文件描述符是否就绪,缺点是一次系统调用只能检查一个文件描述符,fd很多时,系统调用成本很高
- IO多路复用可以通过一次系统调用检查多个fd的状态,相当于把轮询fd的过程从用户态移到了内核态,避免用户态和内核态的频繁切换
- 进程可以通过select,poll,epoll发起IO多路复用的系统调用,是同步阻塞的:有就绪的fd返回若都不就绪则阻塞进程直到timeout,IO多路复用内部使用非阻塞IO检查每个fd状态
- IO多路复用内部实现必须用非阻塞IO(轮询),但不是使用IO多路复用必须用非阻塞IO
- fd 文件描述符 非负整数,标识一个打开的文件
- socket可用于一台主机不同进程的通信也可用于不同主机的通信,创建socket返回fd,进程通过读写fd来和远程主机通信
#### select 缺点:
- 性能开销大:调用select时会陷入内核,需要把参数中的fd_set从用户空间拷贝到内核空间,内核需要遍历传递进来的fd_set的每一位
- 同时能监听的fd受限于siezeof(fd_set)的大小,一般为1024
#### poll
- poll 和 select几乎没有区别,poll在用户态通过数组传递fd,在内核转为链表存储,没有最大数量的限制
- 从性能开销上poll 与 select相差不大
#### epoll
- 使用红黑树存储fd, 使用队列存储就绪的fd,每个fd只在添加时传入一次,通过时间更改描述符状态
- 红黑树是二叉平衡查找树(相对平衡),查找插入删除时间复杂度O(logn)
- epoll_tl 为每个fd指定了回调函数,在就绪时会将其加入到就绪队列,因此不用遍历,只需判断就绪队列是否为空即可,从O(N)降为O(1)
- select只支持水平触发,epoll支持水平触发和边缘触发
- 水平触发:当fd就绪时会触发通知,若用户程序没有一次性读写完,下次还会发出信号通知
- 边缘触发:仅当fd从未就绪变为就绪时通知一次,之后不会再通知
- 边缘触发效率更高,减少事件被重复触发的次数,函数不会返回大量用户程序不需要的fd
#### 为什么边缘触发必须使用非阻塞IO
epoll在边缘触发模式下只会在fd状态变为可读可写时收到操作系统的通知,因此必须使用非阻塞IO,并循环调用read write多次直到返回EWOULDBLOCK,然后调用epoll_wait等待下一次通知,若使用阻塞IO,
会在循环时最后一次调用(无数据可读写)时阻塞
#### 适用场景
当连接数较多并有较多不活跃连接时,epoll效率比其它两者高很多,当连接数较少并都十分活跃时,由于epoll需要很多回调,一次性能可能低于其它两者。
#### Redis线程模型
- redis单线程,使用多路IO复用处理客户端的多个连接
- IO设备速度远远慢于CPU时(磁盘,网络),引入多线程,适用于下层存储慢速场景,为了充分利用CPU的计算资源
- redis 纯内存操作,多线程频繁的上下文切换反而是一种负优化,单线程里并发处理客户端多个连接,减少多线程的系统开销,同时又更好的可维护性方便调试
- redis在最新几个版本也引入多线程目的是异步处理删除操作,当删除超大键值对时,单线程可能会阻塞,应对网络IO
## 算法题
题目不难,最后一道是最大岛屿面积 dfs 但不会处理输入 二维数组没给尺寸
```
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
// 从标准输入读取一行输入
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter a list of numbers separated by spaces: ")
input, _ := reader.ReadString('\n')
// 将输入字符串按空格分割成字符串切片
input = strings.TrimSpace(input)
numbers := strings.Split(input, " ")
// 将字符串切片转换为整型切片
var array []int
for _, number := range numbers {
n, _ := strconv.Atoi(number)
array = append(array, n)
}
// 打印整型切片
fmt.Println(array)
}
```