Python代码实现
import socket
import threading
def handle_client(client_socket, client_address):
try:
print(f"Handling connection from {client_address}")
while True:
data = client_socket.recv(1024)
if not data:
break
# 模拟较长时间的计算操作
result = perform_computation(data)
client_socket.sendall(result)
except Exception as e:
print(f"Error handling client {client_address}: {e}")
finally:
client_socket.close()
def perform_computation(data):
# 实际的计算操作,这里简单返回数据长度
return str(len(data)).encode('utf-8')
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('localhost', 8888)
server_socket.bind(server_address)
server_socket.listen(5)
print(f"Server is listening on {server_address}")
while True:
client_socket, client_address = server_socket.accept()
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
client_thread.start()
if __name__ == "__main__":
start_server()
多线程技术实现需求描述
- 主线程:主线程负责监听TCP连接请求。当有客户端连接时,主线程接受连接并创建一个新的线程来处理该客户端。
- 子线程:每个子线程独立处理一个客户端的请求。子线程从客户端接收数据,进行计算操作(这里模拟为计算数据长度),然后将结果返回给客户端。由于每个客户端由独立的线程处理,所以一个客户端的长时间计算操作不会阻塞其他客户端的请求。
多线程可能带来的问题及解决方案
- 资源竞争问题:多个线程可能同时访问和修改共享资源,导致数据不一致。
- 解决方案:使用锁(
threading.Lock
)来保护共享资源。在访问共享资源前获取锁,访问完成后释放锁。例如:
lock = threading.Lock()
shared_variable = 0
def thread_function():
global shared_variable
with lock:
shared_variable += 1
- 死锁问题:两个或多个线程相互等待对方释放资源,导致所有线程都无法继续执行。
- 解决方案:
- 避免嵌套锁,尽量按照相同的顺序获取锁。
- 使用超时机制,在获取锁时设置超时时间,如果在超时时间内未获取到锁,则放弃并进行相应处理。
- GIL(全局解释器锁)问题:在CPython中,GIL会限制多线程在多核CPU上的并行执行。对于CPU密集型任务,多线程可能无法充分利用多核优势。
- 解决方案:
- 对于CPU密集型任务,可以使用
multiprocessing
模块替代threading
模块,因为multiprocessing
模块基于进程,每个进程有自己独立的Python解释器,不受GIL限制。
- 对于I/O密集型任务,GIL的影响较小,多线程仍然是一个有效的解决方案。