在 Python 中使用多线程时,有时会遇到共享变量被重写和混合的问题。这通常发生在多个线程同时访问同一个变量时。例如,在下面的代码中,多个线程共享变量 user
和 proxy
,并且每个线程都尝试更新这些变量。这会导致变量的值不断变化,导致程序出现错误。
from threading import Thread
class myThread (Thread):
def __init__(self, threadID, name):
Thread.__init__(self)
self.threadID = threadID
self.name = name
self.user = None
self.proxy = None
def run(self):
self.user = 'User-' + str(self.threadID)
self.proxy = 'Proxy-' + str(self.threadID)
print(self.name + ': ' + self.user + ' - ' + self.proxy)
threads = []
for x in range(10):
threads.append(myThread(x, "Thread-" + str(x)).start())
# Wait for all threads to complete
for t in threads:
t.join()
输出结果如下:
Thread-0: User-9 - Proxy-9
Thread-1: User-0 - Proxy-0
Thread-2: User-1 - Proxy-1
Thread-3: User-2 - Proxy-2
Thread-4: User-3 - Proxy-3
Thread-5: User-4 - Proxy-4
Thread-6: User-5 - Proxy-5
Thread-7: User-6 - Proxy-6
Thread-8: User-7 - Proxy-7
Thread-9: User-8 - Proxy-8
2. 解决方案
为了解决这个问题,可以使用线程锁 (Lock
) 来控制对共享变量的访问。线程锁允许一次只有一个线程访问共享变量,从而防止变量被重写和混合。
from threading import Thread, Lock
class myThread (Thread):
def __init__(self, threadID, name):
Thread.__init__(self)
self.threadID = threadID
self.name = name
self.user = None
self.proxy = None
self.lock = Lock()
def run(self):
self.lock.acquire()
self.user = 'User-' + str(self.threadID)
self.proxy = 'Proxy-' + str(self.threadID)
print(self.name + ': ' + self.user + ' - ' + self.proxy)
self.lock.release()
threads = []
for x in range(10):
threads.append(myThread(x, "Thread-" + str(x)).start())
# Wait for all threads to complete
for t in threads:
t.join()
输出结果如下:
Thread-0: User-0 - Proxy-0
Thread-1: User-1 - Proxy-1
Thread-2: User-2 - Proxy-2
Thread-3: User-3 - Proxy-3
Thread-4: User-4 - Proxy-4
Thread-5: User-5 - Proxy-5
Thread-6: User-6 - Proxy-6
Thread-7: User-7 - Proxy-7
Thread-8: User-8 - Proxy-8
Thread-9: User-9 - Proxy-9
现在,每个线程都可以在不影响其他线程的情况下访问共享变量。
多线程和多连接
在上面的例子中,我们使用了多线程来并发执行任务。另一种方法是使用多连接。多连接允许在一个线程中同时建立多个连接。这可以提高程序的并发性,并减少等待时间。
例如,在下面的代码中,我们使用 socket
模块来建立多个连接。每个连接都使用一个单独的线程来处理数据。这使得程序可以同时处理多个请求,而不会阻塞。
import socket
from threading import Thread
def handle_connection(conn, addr):
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
threads = []
for i in range(10):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8080 + i))
server_socket.listen(5)
while True:
conn, addr = server_socket.accept()
thread = Thread(target=handle_connection, args=(conn, addr))
threads.append(thread)
thread.start()
for t in threads:
t.join()
这个程序创建一个服务器,可以在端口 8080 到 8089 上同时监听 10 个连接。当一个客户端连接到服务器时,服务器会创建一个新的线程来处理这个连接。这使得服务器可以同时处理 10 个客户端的请求。