网络并发面试点

一、网络

1.请写出osi五层协议,并写出你知道的三层的物理设备,和四层的协议

应用层、传输层、网络层、数据链路层、物理层

三层设备:路由器、三层交换机;四层协议:tcp协议/udp协议

2.请描述三次握手和四次挥手的过程,这个过程属于哪个协议?

三次握手

accept:服务器接收过程中等待客服端的连接

  1. connect:客户端发起一个syn链接请求
  2. server端响应回复ack的同时还会发送一条syn链接请求
  3. client端回复ack确认后,就建立起一个tcp协议的连接

三次握手的过程再代码中是由accept和connect共同完成的,具体的细节在socket中没有体现出来

四次挥手

server端和client端对应的代码中都有close方法

  • 每一端发起的close操作都是一次fin的断开请求,得到断开确认ack之后,就可以结束一端的数据发送
  • 如果两端都发去close,那么就是两次断开请求和两次确认回复,一共是四次操作。

可以结束两端的数据发送,表示连接断开了

3.tcp协议和udp协议各自的特点,并说明什么是黏包现象,哪一种协议会黏包,为什么?

tcp协议:面向连接的,流式的,可靠地,效率低的全双工通信

udp协议:面向数据报的,无连接的,不可靠,快的,能完成一对一,一对多,多对多的高效通讯协议。

tcp协议出现黏包是因为它无边界的流式传输特点导致的。

二、进程

1.进程间内存是否共享?如何实现通讯?

解析:

进程之间的内存是相互隔离的,因此数据也是相互隔离的。

实现:1.基于文件(队列,管道+锁)2.基于网络(第三方工具,socket)

2、请聊聊进程队列的特点和实现原理?

特点:1.进程安全,2.数据量不宜过大,3.放取值阻塞

实现原理:基于管道+锁的原理,让不同进程对共享数据的修改有序化,从而保证了数据的安全。

3、请画出进程的三状态转换图

img

4、你了解生产者模型消费者模型么?如何实现?

生产者:负责制造数据的任务

消费者:负责将生产者产生的数据进行处理的任务

生产者消费模型:基于生产者产生数据,放入一个共享空间(队列),消费者从中取到数据进行处理的模型。

意义:1.实现了生产者和消费者的解耦合,2.平狠了生产力和消费力,生产者不停生产数据,消费者不停处理数据,二者通过队列进行沟通。

5、从你的角度说说进程在计算机中扮演什么角色?

进程在计算机中类似工厂生产零件的车间,为生产过程开辟空间储备生产所需要的材料,在计算机中对应的就是开辟内存,存储运行代码和数据。

6.什么是IPC,请简述你了解的IPC机制

inter process communication,进程之间通信,基于管道、队列的第三方工具实现(redis,memcache,rabbitmq)

三、线程

1.GIL锁是什么回事?

global interpreter lock全局解释其所,Cpython中,对解释器加的一把锁,导致同一时刻同一进程中只有一个线程能够访问cpu,GIL锁的出现,保证了多线程对共享数据的大部分操作,也就是类原子操作时的数据安全。但是无法避免所有修改共享数据的安全。

2.在python中是否线程安全?

不是,在Cpython解释器中,代码都会转换成机器码,即时有了GIL锁的限制,多线程对数据的非原子性修改操作,也会因为操作系统的对cpu时间片轮转而导致对数据修改的不安全。

3..什么叫做死锁?

多道操作系统中,是指多个进程或线程在执行过程中,因争夺资源而造成的一种互相等待的僵局现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程/线程。

4、logging模块是否是线程安全的?

是,因为logging模块的写入是追加写

5.threading.local的作用?

创建全局ThreadLocal对象:
localVal = threading.local()
localVal.val = "Main-Thread"  # 为全局线程对象赋值

用来保存一个全局变量,只能在当前前线程中才能访问

不同线程对其赋值,不会覆盖,而会在自己的线程单独创建控件来存储这个变量

不同线程的前程变量local.val是隔离的,其他线程无法访问

6、程序从flag a执行到falg b的时间大致是多少秒?

import threading
import time
def _wait():
    time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = False)
t.start()
# flag b

0秒,因为线程的开启速度非常快,而且t.start()是异步非阻塞方法的,不会等待线程中的任务结束。

7、程序从flag a执行到falg b的时间大致是多少秒?

import threading
import time
def _wait():
    time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = True)
t.start()
# flag b

0秒,守护线程结束时间是在所有非守护线程结束后,而该进程中没有其他线程,所以主线程在异步执行start后立马结束,守护线程也被强制结束了。

8、程序从flag a执行到falg b的时间大致是多少秒?

import threading
import time
def _wait():
 time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = True)
t.start()
t.join()
# flag b

10秒,join方法会阻塞,同步等待线程任务执行完成才继续执行下一步

9、读程序,请确认执行到最后number是否一定为0

imgView Code

不一定,多线程对共享数据进行非原子操作,如+=,-=,*=,/=都有可能出现数据不安全。需要加互斥锁保证数据安全。

10.读程序,请确认执行到最后number是否一定为0

imgView Code

一定为0,因为在启动ta和ts后分别对ta,ts进行join,是将ta和ts异步执行变成了同步执行,ts会等待ta执行完毕后才执行,也就是同一时刻,只有一个代码去修改数值,这种修改是安全的。

11、读程序,请确认执行到最后number的长度是否一定为1

imgView Code

一定为1,因为append是不可拆分操作,线程对数据的不可拆分操作不会导致数据不安全,而在每次取值都会等待,也不会出现取到空值报错的现象。所以一定为1。

12、读程序,请确认执行到最后number的长度是否一定为1

imgView Code

一定为1,线程ta和ts是同步执行的,ta执行完后,ts才开始执行,线程同步执行修改数据,数据是安全的。

四、协程

1.什么是协程?常用的协程模块有哪些?协程和线程的区别?

协程是一种用户级的轻量型线程,协程是由用户程序自己控制调度,是单线程下的并发,又称微线程,纤程,coroutine

常用模块:

greenlet:提供了切换任务的快捷方式,但是遇到io无法自动切换任务,需要手动切换

gevent:开启协程任务并切换的模块,遇到io自动切换任务。

2.协程的join使用来做什么的?它是如何发挥作用的?

阻塞等待调用join方法的协程任务执行完毕,然后继续往后执行。

join产生阻塞,gevent识别到阻塞后,自动切换任务,只要该协程任务没有完成,join会一直产生阻塞,从而使gevent不停的切换到该协程任务上执行。

3.使用协程实现并发的tcp server端

img协程实现并发server

4.在一个列表中有多个url,请使用协程访问所有url,将对应的网页内容写入文件保存

img协程访问url

五、综合

1.简述进程、线程、协程的区别以及应用场景?

进程:操作系统资源分配的最小单位,进程之间资源和地址空间独立,进程的创建、销毁、切换开销大,可以利用多核。高密集型计算。

线程:进程中的一条执行过程,操作系统执行的最小单位,共享当前进程的资源,创建、销毁、切换开销比进程小。单存计算模型

协程:基于用户级别控制的,线程中可以自由切换任务,无需操作系统调度,创建比线程更高效。爬虫数据处理。

2.进程池、线程池的优势和特点

开启一定数量的进程/线程不停轮流处理大量的任务,避免了不停开启/销毁线程/进程过程中的开销,从而提高处理任务的效率。

特点:只要有任务未处理完,进程池/线程池会自动开启进程/线程处理任务,知道池中进程/线程数量达到限制。每个进程/线程处理完任务,无需销毁,而是从新指令其他未完成的任务。

3.线程和协程的异同?

1.线程的开启、切换、销毁需要通过操作系统执行,协程的创建、切换、销毁是基于程序员自己控制。

2.协程的切换效率远高于线程的切换

3.协程本质上就是一个线程,所以也无法利用多核。

4.协程是数据安全的,但是线程数据不安全

4.请简述一下互斥锁和递归锁的异同?

不同点:互斥锁不能连续acquire,连续acquire会产生死锁现象;递归锁可以连续的acquire。

相同点:互斥锁和递归锁都可以保证同一段代码在同一时间只有一个线程执行。

5.请列举一个python中数据安全的数据类型?

队列,队列内部自动实现了锁的机制,同一时间只有能一个对象对队列中的元素修改

6、Python中如何使用线程池和进程池

使用concurrent.futures模块中的ProcessPoolExecutor类和ThreadPoolExecutor类,创建进程池和线程池。

p = ProcessPoolExecutor(maxsize)获得进程池对象

t = ThreadPoolExecutor(maxsize)获得线程池对象

使用submit向池中添加任务,获得一个任务对象

对任务对象使用result获取任务的返回值

7.什么是并行,什么是并发?

并行:多个程序在同一时刻使用多个cpu处理任务,是真正的同时运行

并发:多个程序交替在一个cpu上处理任务,看起来像同时运行

8.请解释同步和异步的概念

同步:发起一个任务,原地等待该任务执行结束返回结果,才继续执行后续代码。

异步:发起一个任务,不等待该任务执行结束,就直接执行后续代码。

9.请谈谈对异步非阻塞的了解?

异步非阻塞,执行效率最高的模式,发起任务,不等待结果,直接执行自己的任务,任务在执行过程中没有阻塞操作,充分提高了CPU的计算效率。

10.简述信号量的实现原理?

sem = semaphore(5) 获得一个信号量对象

同一可以允许一定数量的进程/线程执行某一段代码,之后的进程/线程需要等待其中任务释放掉信号量锁,才能获取锁,执行该段代码。

11.程序中的阻塞有哪些?给程序带来了什么影响?

一切io操作即向内存中写入和从内存中取出,如读取文件,写入文件,获取用户数据,

12.请分别使用多进程、多线程、协程实现生产者消费之模型?

原文地址:https://www.cnblogs.com/ryxiong-blog/p/12988763.html