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

Why this 10 threads always output the same thread name?

我运行这个代码

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

您的函数查询 t,但 t 未在函数中定义 :

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

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

现在,由于您在 for 循环 中编写了 t = ...,因此 t 变化很快。 for 循环很可能已经达到最后一个值 - 特别是因为 Python 的线程机制 - 在第一个线程实际获取 t 之前。结果,所有线程获取 t 引用 last 构造的线程。

如果我们 将函数重写为 :

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

在我的机器上。当然,这 not 保证每个线程都会获取 correct 线程,因为有可能只有在进程的后期,线程才会启动工作并获取 t 变量。

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

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

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

注意:如果您目前运行没有方便的访问线程对象,可以使用

threading.currentThread()

得到它。那么

threading.currentThread().getName()

将return线程的名称运行吧。

我建议你试试这个:

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 引用最新线程。