python多线程重入陷阱

多线程使用容易出现重入问题,有时这种重入不易发觉,我们一起看下面这个例子:

import threading
import time


class A:
    def func(self, num):
        self.num = num
        time.sleep(5)
        return self.num


class TestThread(threading.Thread):
    def __init__(self, thread_id, func):
        threading.Thread.__init__(self, name='test')
        self.func = func
        self.thread_id = thread_id

    def run(self):
        num = self.func(self.thread_id)
        print("线程{thread_id}:{num}".format(thread_id=self.thread_id, num=num))


a = A()
th_list = list()
for i in range(5):
    th = TestThread(i, a.func)
    th_list.append(th)

for i in range(5):
    th_list[i].start()

for i in range(5):
    th_list[i].join()

上面这个例子中,多线程类调用了一个类A的成员函数func,而这个func函数会设置A的成员变量num,将线程id传递给func,并且打印返回值,最终的结果如下,发现所有线程中打印出来的数值都是4。

线程1:4
线程0:4
线程2:4
线程3:4
线程4:4

这个的根本原因是:A只有一个实例,虽然传递给各个线程的只是一个成员函数,但这个成员函数可以设置类的成员变量, 这个成员变量因此会被多个线程操纵,造成修改

所以在多线程使用中,谨慎传递类成员函数,因为可以造成变量被覆盖等问题,应当给每个线程实例化自己的对象,调用各个实例自己的成员函数,这样就不会互相干扰。

如下面代码的这种实现方式,就可以解决这个问题:

import threading
import time


class A:
    def func(self, num):
        self.num = num
        time.sleep(5)
        return self.num


class TestThread(threading.Thread):
    def __init__(self, thread_id, Class):
        threading.Thread.__init__(self, name='test')
        a = Class()
        self.func = a.func
        self.thread_id = thread_id

    def run(self):
        num = self.func(self.thread_id)
        print("线程{thread_id}:{num}".format(thread_id=self.thread_id, num=num))


th_list = list()
for i in range(5):
    th = TestThread(i, A)
    th_list.append(th)

for i in range(5):
    th_list[i].start()

for i in range(5):
    th_list[i].join()

线程0:0
线程1:1
线程3:3
线程2:2
线程4:4

你可能感兴趣的:(python多线程重入陷阱)