为什么这10个线程总是输出相同的线程名称?

时间:2017-06-20 00:08:18

标签: python python-3.x python-multithreading

我运行了这段代码

NUM = 0
def count():
    global NUM
    NUM += 1
    time.sleep(1)
    print(t.getName()+":"+"NUM is "+str(NUM))

for i in range(10):
    t = threading.Thread(target=count)
    t.start()

输出

Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10
Thread-10:NUM is 10

我知道为什么NUM总是10,但为什么线程名称总是一样的?每个线程都运行print(t.getName()+":"+"NUM is "+str(NUM)); t不应该是获得cpu时间的线程吗?我认为名称不应该相同。

当我改为

NUM = 0
def count():
    global NUM
    NUM += 1
    name = t.getName()
    time.sleep(1)
    print(name+":"+"NUM is "+str(NUM))

for i in range(10):
    t = threading.Thread(target=count)
    t.start()

它按预期工作:

Thread-1:NUM is 10
Thread-3:NUM is 10
Thread-2:NUM is 10
Thread-4:NUM is 10
Thread-5:NUM is 10
Thread-7:NUM is 10
Thread-10:NUM is 10
Thread-9:NUM is 10
Thread-6:NUM is 10
Thread-8:NUM is 10

4 个答案:

答案 0 :(得分:7)

这是因为您引用了全局名称t。当休眠结束时,循环结束,t仍然绑定到循环创建的最后一个线程(第10个线程)。

在您的替代方案中,结果实际上并未定义。在那里你引用全局t ,而循环仍然在运行,所以它很可能被绑定到最近创建的线程 - 但是没有到是

注意:如果您无法方便地访问当前正在运行的线程对象,则可以使用

threading.currentThread()

得到它。然后

threading.currentThread().getName()

将返回运行它的线程的名称。

答案 1 :(得分:4)

您的函数查询t,但函数中定义了t

def count():
    global NUM
    NUM += 1
    name = t.getName() # use outer t
    time.sleep(1)
    print(name+":"+"NUM is "+str(NUM))

Python的回退机制因此将在直接外部范围内寻找t。实际上,您在外部范围内分配了t,因此它将采用该值。

现在,因为您在t = ...循环中编写 fort会迅速变化。 for循环很可能已经达到了最后一个值 - 特别是因为Python的线程机制 - 在第一个线程实际获取t之前。因此,所有线程都会根据 last 构造的线程获取t

如果我们将该功能重写为

NUM = 0
def count():
    name = t.getName() # t fetched immediately
    global NUM
    NUM += 1
    time.sleep(1)
    print(name+":"+"NUM is "+str(NUM))

我明白了:

Thread-11:NUM is 10
Thread-12:NUM is 10
Thread-13:NUM is 10
Thread-14:NUM is 10
Thread-15:NUM is 10
Thread-17:NUM is 10
Thread-16:NUM is 10
Thread-19:NUM is 10
Thread-18:NUM is 10
Thread-10:NUM is 10

在我的机器上。当然,保证每个线程都会获取正确的线程,因为有可能只是在进程的后期,线程才会开始工作并获取{{ 1}}变量。

答案 2 :(得分:2)

线程名称和计数NUM都有同样的问题:当你到达第一个print语句时,所有10个线程都已启动。您只有一个全局变量t用于该线程,一个全局NUM用于该计数。因此,您看到的只是最后一个值,即第10个线程的值。如果您希望打印单独的值,则需要为代码提供一种机制,以便在它们启动时对其进行报告,或者保留一个可以迭代的列表。

答案 3 :(得分:1)

我建议你试试这个:

NUM = 0
def count():
    global NUM
    NUM += 1
    num = NUM
    name = t.getName()
    time.sleep(1)
    print("t.getName: " + t.getName() + ", name: " + name + ":" + ", NUM: " + str(NUM) + ", num: " + str(num))

for i in range(10):
    t = threading.Thread(target=count)
    t.start()

结果:

t.getName: Thread-10, name: Thread-10:, NUM: 10, num: 10
t.getName: Thread-10, name: Thread-6:, NUM: 10, num: 6
t.getName: Thread-10, name: Thread-3:, NUM: 10, num: 3
t.getName: Thread-10, name: Thread-5:, NUM: 10, num: 5
t.getName: Thread-10, name: Thread-4:, NUM: 10, num: 4
t.getName: Thread-10, name: Thread-9:, NUM: 10, num: 9
t.getName: Thread-10, name: Thread-7:, NUM: 10, num: 7
t.getName: Thread-10, name: Thread-2:, NUM: 10, num: 2
t.getName: Thread-10, name: Thread-1:, NUM: 10, num: 1
t.getName: Thread-10, name: Thread-8:, NUM: 10, num: 8

t.getName()是一个函数调用,它是一个引用。当打印功能到达控制台时,t引用最新的线程。