Python - threading 模块使用

详细学习一下 Python 的线程使用方法

单线程

以逛吃为栗子,开始编码……
在这里插入图片描述
程序的意思就是:今天媳妇要逛街,逛街需要体力啊~ 所以我们先吃饭,吃饱了然后就购物,直到钱包发出警报~ 一共花费时间8秒钟。

单线程:做完一件事再去做另一件事。

媳妇说了,干吃干逛多没劲,你得让我发表意见啊~好,完善一下程序,编码开始……
在这里插入图片描述
OK,加入自定义参数arg,满足需求。

多线程

还是那个媳妇,还是那条街;
媳妇又想逛街了,嫌吃饭太耽误时间,想多逛一会儿,好了,去商场~
逛~吃~逛~吃~开火车~

多线程:多件事情同时做。

启动线程 -> t.start()

源码文档

"""Start the thread's activity.

It must be called at most once per thread object. It arranges for the
object's run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the
same thread object.

"""

该方法为启动线程,每个线程最多只能调用一次,多次调用则会引发RuntimeError错误。调用的其实是线程的run()方法。

吃个栗子:

import threading
from time import ctime, sleep


def c_time():
    return ctime().split(' ')[3]


def eat(arg):
    for i in range(2):
        # 获取当前线程名称:threading.current_thread().getName()
        print("%s | %s | 吃 -> %s" % (threading.current_thread().getName(), c_time(), arg))
        sleep(1)


def shopping(arg):
    for i in range(2):
        print("%s | %s | 逛 -> %s" % (threading.current_thread().getName(), c_time(), arg))
        sleep(3)


threads = []
# target -> 调用的方法;args -> 对 eat 进行传参;name -> 线程名
t1 = threading.Thread(target=eat, args=('烤面筋',), name='t1')
t2 = threading.Thread(target=shopping, args=('奥特莱斯',), name='t2')
threads.append(t1)
threads.append(t2)


if __name__ == '__main__':
    for t in threads:
        t.start()

    print("\r%s | %s | 叮~!余额不足..." % (threading.current_thread().getName(), c_time()))

执行结果 >>>

t1 | 14:34:41 | 吃 -> 烤面筋
t2 | 14:34:41 | 逛 -> 奥特莱斯
MainThread | 14:34:41 | 叮~!余额不足...
t1 | 14:34:42 | 吃 -> 烤面筋
t2 | 14:34:44 | 逛 -> 奥特莱斯

Process finished with exit code 0

主线程跟其他线程同一时间启动,主线程执行完后,子线程会继续执行。

守护线程 - t.setDaemon()

首先看下源码如何使用
在这里插入图片描述
文档说明该方法通过一个bool值来指出是否为守护线程。而且必须在start()方法前调用,主线程默认为False。如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print()后,没有等待子线程,直接就退出了,同时子线程也一同结束。

吃个栗子:

...
if __name__ == '__main__':
    for t in threads:
        t.setDaemon(True)  # 设置守护进程
        t.start()

    print("\r%s | %s | 叮~!余额不足..." % (threading.current_thread().getName(), c_time()))

执行结果 >>>

t1 | 14:57:16 | 吃 -> 烤面筋
t2 | 14:57:16 | 逛 -> 奥特莱斯
MainThread | 14:57:16 | 叮~!余额不足...

Process finished with exit code 0

可以看到,t1 t2未执行第二次循环就直接结束了,且三个线程的开始时间都是相同的。

线程等待 - t.join()

源码文档阅读

"""Wait until the thread terminates.

 This blocks the calling thread until the thread whose join() method is
 called terminates -- either normally or through an unhandled exception
 or until the optional timeout occurs.

 When the timeout argument is present and not None, it should be a
 floating point number specifying a timeout for the operation in seconds
 (or fractions thereof). As join() always returns None, you must call
 isAlive() after join() to decide whether a timeout happened -- if the
 thread is still alive, the join() call timed out.

 When the timeout argument is not present or None, the operation will
 block until the thread terminates.

 A thread can be join()ed many times.

 join() raises a RuntimeError if an attempt is made to join the current
 thread as that would cause a deadlock. It is also an error to join() a
 thread before it has been started and attempts to do so raises the same
 exception.

 """

大概意思为:用于等待线程结束。阻塞主线程,直到子线程执行完毕。

吃个栗子:

...
if __name__ == '__main__':
    t = None
    for t in threads:
        t.setDaemon(True)
        t.start()
    t.join()
    print("\r%s | %s | 叮~!余额不足..." % (threading.current_thread().getName(), c_time()))

执行结果 >>>

t1 | 15:15:44 | 吃 -> 烤面筋
t2 | 15:15:44 | 逛 -> 奥特莱斯
t1 | 15:15:45 | 吃 -> 烤面筋
t2 | 15:15:47 | 逛 -> 奥特莱斯
MainThread | 15:15:50 | 叮~!余额不足...

Process finished with exit code 0

此时t.join()for循环外,所以会等for循环执行完毕,才会去执行主进程。从执行结果可以看到,两个线程是同时启动的,总耗时6秒。相比单线程节省了2秒的时间。

如果t.join()放在for循环内,线程会依次执行,相当于单线程了。输出如下:

t1 | 15:26:00 |-> 烤面筋
t1 | 15:26:01 |-> 烤面筋
t2 | 15:26:02 |-> 奥特莱斯
t2 | 15:26:05 |-> 奥特莱斯
MainThread | 15:26:08 | 叮~!余额不足...

Process finished with exit code 0

t.join()还可以设置最大等待时间,超过设置时间后,就直接执行主进程,不再等待子进程运行完毕。

吃个栗子:

...
if __name__ == '__main__':
    t = None
    for t in threads:
        t.setDaemon(True)
        t.start()
    t.join(1)  # 设置最长等待时间
    print("\r%s | %s | 叮~!余额不足..." % (threading.current_thread().getName(), c_time()))

执行结果 >>>

t1 | 16:15:34 | 吃 -> 烤面筋
t2 | 16:15:34 | 逛 -> 奥特莱斯
t1 | 16:15:35 | 吃 -> 烤面筋
MainThread | 16:15:35 | 叮~!余额不足...

Process finished with exit code 0

只输出 1 秒内做的事情~超过 1 秒后执行主线程结束,子线程也终止。

参考文档:Python threading 官方文档

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值