1、解释以下什么是锁,有哪几种锁?
-
锁(Lock)是python提供的对线程控制的对象。
-
有互斥锁,可重入锁,死锁。
2、什么是死锁?互斥锁?
- 若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
- 互斥锁(Mutex)是个提供线程同步的基本锁
3、多线程交互访问数据,怎么避免重读?
创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,在多线程访问数据的时候先查看数据是否在已访问的列表中,若已存在就直接跳过。
4、什么是线程安全?
- 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
- 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
5、说说下面几个概念:同步,异步,阻塞,非阻塞
- 同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。
- 异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
- 阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
- 非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的。
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
6、什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
-
孤儿进程: 父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被 init 进程(进程号为1)所收养,并由 init 进程对他们完成状态收集工作。
-
僵尸进程: 进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。
避免僵尸进程的方法:
- fork 两次用孙子进程去完成子进程的任务
- 用 wait() 函数使父进程阻塞
- 使用信号量,在 signal handler 中调用 waitpid,这样父进程不用阻塞。
7、python中进程与线程的使用场景?
-
多进程适合在CPU密集操作(cpu操作指令比较多,如位多的的浮点运算)。
-
多线程适合在IO密性型操作(读写数据操作比多的的,比如爬虫)
8、线程是并发还是并行,进程是并发还是并行?
- 线程是并发,进程是并行;
进程之间互相独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。
9、并行(parallel)和并发(concurrency)?
并行 | 并发 |
---|---|
同一时刻多个任务同时在运行 | 不会在同一时刻同时运行,存在交替执行的情况。 |
实现并行的库有:multiprocessing | 实现并发的库有: threading |
-
程序需要执行较多的读写、请求和回复任务的需要大量的IO操作,IO密集型操作使用并发更好。
-
CPU运算量大的程序,使用并行会更好
10、IO密集型和CPU密集型区别?
-
IO密集型: 系统运行,大部分的状况是CPU在等 I/O(硬盘/内存)的读/写
-
CPU密集型: 大部分时间用来做计算,逻辑判断等CPU动作的程序称之CPU密集型。
11、谈谈你对多进程,多线程,以及协程的理解
-
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。
-
线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
-
协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
12、Python异步使用场景有那些?
异步的使用场景:
- 不涉及共享资源,对共享资源只读,即非互斥操作
- 没有时序上的严格关系
- 不需要原子操作,或可以通过其他方式控制原子性
- 常用于IO操作等耗时操作,因为比较影响客户体验和使用性能
- 不影响主线程逻辑
13、什么是多线程竞争?
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态,造成数据混乱,即所谓的线程不安全。
14、怎么解决多线程竞争问题?
锁
-
锁的好处: 确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。
-
锁的坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。
15、Windows下的内存是如何管理的
- 虚拟内存:
最适合用来管理大型对象或者结构数组 - 内存映射文件:
最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行多个进程之间共享数据 - 内存堆栈:
最适合用来管理大量的小对象
16、中断和轮询的特点
- 轮询效率低,等待时间很长,CPU利用率不高
- 中断容易遗漏一些问题,CPU利用率高。
17、进程间通信有哪些方式?
通信方式 | 说明 |
---|---|
管道(pipe) | 速度慢、容量有限 |
命名管道(named pipe) | 半双工的通信方式 |
信号(signal) | 用于通知接收进程某一事件已经发生 |
信号量(semophere) | 不能传递复杂信息,只能用来同步。 |
消息队列(message queue) | 容量受到系统限制 |
共享内存(shared memory) | 能够很容易控制容量,速度快,但要保持同步 |
套接字(socket) | 是进程间的通信机制,可用于不同进程间的通信。 |