如何解决多线程程序中的的卡顿和堵塞问题

119 阅读1分钟

编写了一段网络程序,其中涉及到使用线程来进行多客户端连接,当主线程开始等待连接时,程序会卡住。另外,发送数据时客户端程序会堵塞。

  • 代码示例:
obj.HOST = ""
obj.PORT = int(port.get())
obj.srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
obj.srv.bind((obj.HOST, obj.PORT))
obj.srv.listen(1)
obj.sock, obj.addr = obj.srv.accept()

class Client(threading.Thread):
    def __init__(self, from_):
        if from_.ip.get() == '':
            obj.HOST = 'localhost'
        else:
            obj.HOST = from_.ip.get()
        obj.PORT = int(from_.port.get())
        obj.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        obj.sock.connect((obj.HOST, obj.PORT))
        threading.Thread.__init__(self)

    def run(self):
        command = obj.sock.recv(1024)
        print(command)
        if command == 'confirm':
            print('confirm')
        elif command == 'start':
            print('start')

client = Client(cl)  # cl is class, where I get port. It's works 100% correct
client.start()
 ```

2. 解决方案

  • 问题一:主线程卡顿的问题可以通过使用 threading.Event() 来解决。

# Create an event to signal that a connection has been established.
connection_event = threading.Event()

def accept_connection():
    """
    Wait for a connection and set the connection_event to signal that a connection has been established.
    """
    obj.srv.listen(1)
    obj.sock, obj.addr = obj.srv.accept()
    connection_event.set()

# Create a thread to handle accepting connections.
connection_thread = threading.Thread(target=accept_connection)
connection_thread.start()

# Wait for the connection event to be set, indicating that a connection has been established.
connection_event.wait()
 ```
  • 问题二:客户端接收数据时堵塞的问题可以通过使用 select.select() 来解决。

while True:
    # Wait for data to be available on the socket.
    ready_to_read, _, _ = select.select([obj.sock], [], [], 0)

    # If data is available, read it and process it.
    if obj.sock in ready_to_read:
        data = obj.sock.recv(1024)
        if data:
            print(data)
        else:
            break
 ```
  • 最终的代码示例:
obj.HOST = ""
obj.PORT = int(port.get())
obj.srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
obj.srv.bind((obj.HOST, obj.PORT))

# Create an event to signal that a connection has been established.
connection_event = threading.Event()

def accept_connection():
    """
    Wait for a connection and set the connection_event to signal that a connection has been established.
    """
    obj.srv.listen(1)
    obj.sock, obj.addr = obj.srv.accept()
    connection_event.set()

# Create a thread to handle accepting connections.
connection_thread = threading.Thread(target=accept_connection)
connection_thread.start()

# Wait for the connection event to be set, indicating that a connection has been established.
connection_event.wait()

class Client(threading.Thread):
    def __init__(self, from_):
        if from_.ip.get() == '':
            obj.HOST = 'localhost'
        else:
            obj.HOST = from_.ip.get()
        obj.PORT = int(from_.port.get())
        obj.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        obj.sock.connect((obj.HOST, obj.PORT))
        threading.Thread.__init__(self)

    def run(self):
        while True:
            # Wait for data to be available on the socket.
            ready_to_read, _, _ = select.select([obj.sock], [], [], 0)

            # If data is available, read it and process it.
            if obj.sock in ready_to_read:
                data = obj.sock.recv(1024)
                if data:
                    print(data)
                else:
                    break

client = Client(cl)  # cl is class, where I get port. It's works 100% correct
client.start()
 ```