面试题答案
一键面试并发模型选择及优缺点
- 多线程:
- 优点:线程间共享进程资源,创建和销毁开销相对较小,适合I/O密集型任务,在Python中可以方便地使用
threading
模块实现。 - 缺点:由于Python的全局解释器锁(GIL),在CPU密集型任务中无法利用多核优势,且线程同步需要小心处理,否则容易出现死锁等问题。
- 优点:线程间共享进程资源,创建和销毁开销相对较小,适合I/O密集型任务,在Python中可以方便地使用
- 多进程:
- 优点:每个进程有独立的内存空间,不存在GIL问题,可以充分利用多核CPU,适合CPU密集型任务。
- 缺点:进程间通信相对复杂,创建和销毁开销较大,占用资源较多。
- 异步I/O:
- 优点:通过事件循环和协程,能在单线程内处理多个I/O操作,高效利用资源,非常适合I/O密集型任务,代码简洁,无需复杂的线程或进程管理。
- 缺点:编程模型相对新,对于习惯传统同步编程的开发者可能不太容易理解,调试相对困难,对CPU密集型任务支持不佳。
这里选择多线程并发模型,因为计算平均值属于简单计算,主要的开销在于网络I/O,多线程在I/O密集场景有较好表现且实现相对简单。
代码实现
import socket
import threading
def handle_client(client_socket):
try:
data = client_socket.recv(1024).decode('utf - 8')
num_list = list(map(int, data.split(',')))
avg = sum(num_list) / len(num_list) if num_list else 0
client_socket.send(str(avg).encode('utf - 8'))
except Exception as e:
print(f"Error handling client: {e}")
finally:
client_socket.close()
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8888))
server_socket.listen(5)
print("Server is listening on port 8888...")
while True:
client_socket, client_addr = server_socket.accept()
print(f"Accepted connection from {client_addr}")
client_thread = threading.Thread(target=handle_client, args=(client_socket,))
client_thread.start()
if __name__ == "__main__":
start_server()
handle_client
函数:负责处理单个客户端连接。接收客户端发送的数据,将其转换为整数列表并计算平均值,然后将平均值返回给客户端。如果出现异常,打印错误信息并关闭连接。start_server
函数:创建TCP服务器套接字,绑定到本地地址和端口8888并开始监听。每当有新客户端连接时,创建一个新线程来处理该客户端。if __name__ == "__main__"
:确保start_server
函数在直接运行脚本时被调用。