Python多线程实现与有序性控制:threading.join()详解

山间有风
山间有风
发布时间:2026-10-15 | 5人浏览过
原创

本文探讨Python中多线程编程的全局变量竞争问题,通过实例展示线程执行无序导致的计算错误,并详细解析如何利用threading.join()方法确保线程按序执行,同时介绍Thread类的常用参数配置。

前言

多线程编程通常用于并行执行多个函数,CPU时间片会在不同任务间轮流分配。其主要优势在于提升CPU利用率,从而缩短处理多项任务的总耗时;然而,若多个线程同时修改全局变量,极易引发数据竞争和计算错误。为解决此问题,常需借助join方法或改用局部变量。Python通过threading模块实现多线程,其中threading.join()的作用在于阻塞当前线程,直至被join的子线程执行完毕,进而保障线程执行的有序性。

一、多线程运行无序问题

首先创建三个线程实例t1、t2和t3。其中,t1调用function1函数,而t2和t3均调用function11函数。这三个函数共同操作全局变量l1。

代码如下:

import threading,time
l1 = []
#创建RLock锁,acquire几次,release几次
lock = threading.RLock()
def function1(x,y):
    for i in range(x):
        l1.append(i)
        if i == 0:
            time.sleep(1)
    end_time = time.time()
    print("t{} is finished in {}s".format(y,end_time -time1 ))
def function11(x,y):
    for i in range(x):
        l1.append(i)
    end_time = time.time()
    print("t{} is finished in {}s".format(y, end_time -time1))
#2.创建子线程:thread类
if __name__ == '__main__':
    t1 = threading.Thread(target= function1, args = (100,1))
    t2 = threading.Thread(target= function11, args = (100,2))
    t3 = threading.Thread(target= function11, args = (100,3))
    time1 = time.time()
    print("time starts in {}".format(time1))
    t1.start()
    t2.start()
    t3.start()
    print(l1)

结果如下:

runfile('E:/桌面/temp.py', wdir='E:/桌面') time starts in 1656474963.9487 t2 is finished in 0.0s t3 is finished in 0.0s [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] t1 is finished in 1.0152690410614014s

观察输出结果可见,全局变量列表开头出现了两个0,而非预期的0, 1, 2, 3...顺序填充。这表明在多线程环境下,全局变量被多个函数无序调用,导致数据交错。为确保多线程对全局变量的有序调用,可引入threading.join()方法进行处理。

二、“join方法”解决多线程运行无序问题

此处重写function1函数并命名为function2,由t1调用function2。t2和t3保持不变。

代码如下:

import threading,time
l1 = []
#创建RLock锁,acquire几次,release几次
lock = threading.RLock()
def function1(x,y):
    for i in range(x):
        l1.append(i)
        if i == 0:
            time.sleep(1)
    end_time = time.time()
    print("t{} is finished in {}s".format(y,end_time -time1))
def function11(x,y):
    for i in range(x):
        l1.append(i)
    end_time = time.time()
    print("t{} is finished in {}s".format(y,end_time -time1))
def function2(x,y):
    for i in range(x):
        l1.append(i)
        if i == 0:
            time.sleep(1)
    end_time = time.time()
    print("t{} is finished in {}s".format(y,end_time -time1))
#2.创建子线程:thread类
if __name__ == '__main__':
    t1 = threading.Thread(target= function2, args = (100,1))
    t2 = threading.Thread(target= function11, args = (100,2))
    t3 = threading.Thread(target= function11, args = (100,3))
    time1 = time.time()
    print("time starts in {}".format(time1))
    t1.start()
    t1.join()
    t2.start()
    t3.start()
    print(l1)

结果如下:

runfile('E:/桌面/temp.py', wdir='E:/桌面') time starts in 1656476057.441827 t1 is finished in 1.0155227184295654s t2 is finished in 1.0155227184295654s t3 is finished in 1.0155227184295654s [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

由此可见,threading.join()方法能够有效解决多线程运行无序的问题。

三、threading.Thread()的常用参数

1.group:默认值None,为未来实现ThreadGroup类而保留。 2.target:在start方法中调用的可调用对象,即需要开启线程的具体函数或方法。 3.name:默认为“Thread-N”,用于指定字符串形式的线程名称。 4.args:默认为空元组,用于向target指定的可调用对象传递参数元组。 5.kwargs:默认为空字典{},用于向target指定的可调用对象传递关键字参数字典。 6.daemon:默认为None,决定线程是否为守护线程。

总结

至此,关于Python多线程实现及有序性控制的介绍完毕。如需了解更多Python多线程相关内容,建议搜索本站过往文章或继续浏览后续系列。感谢大家的支持!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表