Python 多线程的创建与使用

问题

进程(Process)是一个具有一定独立功能的程序关于某个数据集合的一次运行活动
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

那么多线程有什么作用呢?

分析

在讲解线程之前,先看看如下一段代码:

from threading import current_thread
import time


def func1(name):
    print(f'当前线程:{current_thread()}')  # 查看当前运行的线程
    print(f'Threading:{name} start')
    time.sleep(2)
    print(f'Threading:{name} end')


if __name__ == '__main__':
    print(f'当前线程:{current_thread()}')
	
    start = time.time()  # 起始时间

    func1('t1')
    func1('t2')
	
    end = time.time()  # 结束时间
    print(f'运行时间:{end - start}')
    print('主线程结束!')


运行结果如下:
在这里插入图片描述

current_thread() 可以查看当前程序所在的线程,由此可以看到,从开始到结束,就只有一个主线程 MainThread。func1('t1')func1('t2') 这两个函数运行时是串行的,所以运行的时间总共需要 4 秒左右。

可是如果当我们除了一个主线程之外,每次调用 func() 函数都开一个子线程呢?运行时间会有什么变化?

再看看以下代码:

from threading import Thread, current_thread
import time


def func1(name):
    print(f'当前线程:{current_thread()}')  # 查看当前运行的线程
    print(f'Threading:{name} start')
    time.sleep(2)
    print(f'Threading:{name} end')


if __name__ == '__main__':
    print(f'当前线程:{current_thread()}')
    # 创建线程
    t1 = Thread(target=func1, args=('t1',))
    t2 = Thread(target=func1, args=('t2',))

    start = time.time()

    # 开始线程
    t1.start()
    t2.start()

    # func1('t1')
    # func1('t2')

    end = time.time()
    print(f'运行时间:{end - start}')
    print('主线程结束!')


咱们把原来调用 func() 函数的代码先注释掉,同时对应每次调用 func() 函数开启两个子线程,线程的执行统一通过 start() 方法,Thread() 方法中第一个参数传入要调用的函数名,第二个参数传入调用函数需要传入的参数,用元组包装,再来看看运行结果:
在这里插入图片描述

添加两个线程后,运行时间是变快了,不过真有这么快吗,另外主线程结束了,两个子线程竟然还没结束!这肯定不是我们想要的结果…

那如果在开始线程之前加上两句代码:t1.setDaemon(True)t2.setDaemon(True),那么结果又会怎样呢?

# 开始线程
    t1.setDaemon(True)
    t1.start()
    t2.setDaemon(True)
    t2.start()


运行结果:
在这里插入图片描述

我们看到,主线程结束之后,所有子线程也同时结束。

线程在分法有:

  • 主线程:程序的本身
  • 子线程:在程序另开起的线程

注意:在行为上还有一种叫守护线程,主要的特征是它的生命周期。主线程死亡,它也就随之死亡

不过虽然主线程和子线程都同时结束了,不过两个子线程是被强制结束的,并没有运行完成,所以还没有达到我们的要求,那有什么方法真正满足我们的需求呢?革命尚未成功,同志还需努力!

这个方法就是使用 join() 方法:

  • 主线程不会等待子线程运行结束,如果需要等待可使用 join() 方法
  • 不要启动线程后立即 join(),很容易造成串行运行,导致并发失效

示例代码:

from threading import Thread, current_thread
import time


def func1(name):
    print(f'当前线程:{current_thread()}')  # 查看当前运行的线程
    print(f'Threading:{name} start')
    time.sleep(2)
    print(f'Threading:{name} end')


if __name__ == '__main__':
    print(f'当前线程:{current_thread()}')
    # 创建线程
    t1 = Thread(target=func1, args=('t1',))
    t2 = Thread(target=func1, args=('t2',))

    start = time.time()

    # 开始线程
    t1.start()
    t2.start()

    # 等待线程
    t1.join()
    t2.join()

    # func1('t1')
    # func1('t2')

    end = time.time()
    print(f'运行时间:{end - start}')
    print('主线程结束!')


再来运行下看下结果:
在这里插入图片描述
所有线程运行完只花了 2 秒左右的时间,说明两个子线程实现了并发运行,与我们的需求相符。

多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一 样。当然,真正地同时执行多线程需要多核 CPU 才可能实现。

解决

Python 的标准库提供了两个模块:_thread 和 threading,_thread 是低级模块, threading 是高级模块,对_thread 进行了封装。绝大多数情况下,我们只需要使用 threading 这个高级模块来创建线程。

线程的创建有两种方式:

  • 方法包装
  • 类包装
方法包装

多线程可以通过循环开启:

from threading import Thread, current_thread
import time


def func1(name):
    print(f'当前线程:{current_thread()}')  # 查看当前运行的线程
    print(f'Threading:{name} start')
    time.sleep(2)
    print(f'Threading:{name} end')


if __name__ == '__main__':
    print(f'当前线程:{current_thread()}')
    # 创建线程
    t1 = Thread(target=func1, args=('t1',))
    t2 = Thread(target=func1, args=('t2',))

    start = time.time()

    # 循环创建多个线程
    thread_list = []
    for i in range(10):
        t = MyThread(f't{i + 1}')
        t.start()
        thread_list.append(t)

    for t in thread_list:
    	t.join()

    end = time.time()
    print(f'运行时间:{end - start}')
    print('主线程结束!')


运行结果:

当前线程:<_MainThread(MainThread, started 8236)>
当前线程:<Thread(Thread-1, started 8476)>
Threading:t1 start
当前线程:<Thread(Thread-2, started 18236)>
Threading:t2 start
当前线程:<Thread(Thread-3, started 15412)>
Threading:t3 start
当前线程:<Thread(Thread-4, started 15532)>
Threading:t4 start
当前线程:<Thread(Thread-5, started 10044)>
Threading:t5 start
当前线程:<Thread(Thread-6, started 12060)>
Threading:t6 start
当前线程:<Thread(Thread-7, started 1824)>
Threading:t7 start
当前线程:<Thread(Thread-8, started 6292)>
Threading:t8 start
当前线程:<Thread(Thread-9, started 11008)>
Threading:t9 start
当前线程:<Thread(Thread-10, started 13488)>
Threading:t10 start
Threading:t1 end
Threading:t2 end
Threading:t4 end
Threading:t3 end
Threading:t7 end
Threading:t6 end
Threading:t8 end
Threading:t10 end
Threading:t9 end
Threading:t5 end
运行时间:2.0024218559265137
主线程结束!
类包装

自定义 MyThread 类继承自 Thread 类,初始化方法要继承父类的初始化方法,实例方法的名称必须为 run。

from threading import Thread, current_thread
import time


# 类实现-多线程
class MyThread(Thread):
    def __init__(self, name):
        super(MyThread, self).__init__()
        self.name = name

    def run(self):
        print(f'当前线程:{current_thread()}')
        print(f'Threading:{self.name} start')
        time.sleep(2)
        print(f'Threading:{self.name} end')


if __name__ == '__main__':
    print(f'当前线程:{current_thread()}')

    start = time.time()
    
    # 循环创建多个线程
    thread_list = []
    for i in range(10):
        t = MyThread(f't{i + 1}')
        t.start()
        thread_list.append(t)

    for t in thread_list:
        t.join()

    end = time.time()
    print(f'运行时间:{end - start}')


运行结果:

当前线程:<_MainThread(MainThread, started 10004)>
当前线程:<MyThread(t1, started 5816)>
当前线程:<MyThread(t2, started 18444)>
Threading:t2 start
当前线程:<MyThread(t3, started 17092)>
Threading:t3 start
当前线程:<MyThread(t4, started 14200)>
Threading:t4 start
Threading:t1 start
当前线程:<MyThread(t5, started 12076)>
Threading:t5 start
当前线程:<MyThread(t6, started 11204)>
Threading:t6 start
当前线程:<MyThread(t7, started 8044)>
Threading:t7 start
当前线程:<MyThread(t8, started 14776)>
Threading:t8 start
当前线程:<MyThread(t9, started 15060)>
Threading:t9 start
当前线程:<MyThread(t10, started 4904)>
Threading:t10 start
Threading:t5 end
Threading:t6 end
Threading:t4 end
Threading:t2 end
Threading:t3 end
Threading:t1 end
Threading:t9 end
Threading:t10 end
Threading:t8 end
Threading:t7 end
运行时间:2.0033164024353027
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值