Python 线程创建和传参 - Python零基础入门教程

目录

零基础 Python 学习路线推荐 : Python 学习目录 >> Python 基础入门

在以前的文章中虽然我们没有介绍过线程这个概念,但是实际上前面所有代码都是线程,只不过是单线程,代码由上而下依次执行或者进入 main 函数执行,这样的单线程也称为主线程

有了单线程的话,什么又是多线程?可以这么理解:一个线程执行一个代码块,多个线程可以同时执行多个代码,使用多线程能让程序效率更高。举个例子,你今天有两件事需要完成,分别是洗衣服和打扫房间,分别来看看单线程和多线程如何完成:

单线程:先用洗衣机洗衣服30分钟,等衣服洗完之后再打扫房间60分钟,累计总耗时:90分钟;

多线程:把衣服放到洗衣机并且30分钟后自动结束,然后立刻开始打扫房间60分钟,累计耗时:60分钟;

由此可见,完成同样的事情,单线程是一件事情做完之后继续下一件事情,而多线程可以同时执行多件事情,所以多线程比单线程效率更高!

一.Python 线程解释

线程是 cpu 最小调度单位,一个程序中至少有一个或者多个线程(至于进程暂时不做讲解,后面文章会有详细解释)!在开发中使用线程可以让程序运行效率更高,多线程类似于同时执行多个不同代码块。

二.Python 线程创建和启动

1.导入线程模块

# 导入线程threading模块
import threading

2.创建线程并初始化线程

调用 threading 模块中的缺省函数 Thread ,创建并初始化线程,返回线程句柄。如果对缺省函数已经忘记的小伙伴请回到 Python 函数的声明和定义中关于缺省参数部分复习一下。

# 创建并初始化线程,返回线程句柄
t = threading.Thread(target=函数名)

3.启动线程

通过初始化返回的线程句柄调用 start 函数,启动线程,此时会自动执行在创建线程时 target 对应的函数内部的代码:

# 启动线程
t.start()

综合上面三步,下面使用代码对 Python 线程 thread 做详细讲解:

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:猿说编程
@Blog(个人博客地址): www.codersrc.com
@File:Python 线程创建和传参.py
@Time:2021/04/24 08:00
@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""


# 导入线程threading模块
import threading
# 导入内置模块time
import time

def wash_clothes():
    print("洗衣服开始...")
    # sleep 5 秒,默认以秒为单位
    time.sleep(5)
    print("洗衣服完成...")

def clean_room():
    print("打扫房间开始...")
    # sleep 5 秒,默认以秒为单位
    time.sleep(5)
    print("打扫房间完成...")

if __name__ == "__main__":

    # 创建线程并初始化 -- 该线程执行wash_clothes中的代码
    t1 = threading.Thread(target=wash_clothes)
     # 创建线程并初始化 -- 该线程执行clean_room中的代码
    t2 = threading.Thread(target=clean_room)

    t1.start()
    t2.start()


'''
输出结果:

洗衣服开始...
打扫房间开始...
洗衣服完成...
打扫房间完成...
'''

运行程序可以发现程序从运行开始到结束,一共耗时 5 秒时间!注意观察输出日志:

  • 第一步:洗衣服开始和打扫房间开始几乎同时开始,两个事件同时执行.
  • 第二步:程序停止 5 秒;
  • 第三步:洗衣服和打扫房间几乎同时完成

当然你也可以按照以前的学习的内容,先调用 wash_clothes 函数,在调用 clean_room 函数,同样能输出内容,而耗时却是 10 秒左右,示例代码如下:

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:猿说编程
@Blog(个人博客地址): www.codersrc.com
@File:Python 线程创建和传参.py
@Time:2021/04/24 08:00
@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""


# 导入内置模块time
import time

def wash_clothes():
    print("洗衣服开始...")
    # sleep 5 秒,默认以秒为单位
    time.sleep(5)
    print("洗衣服完成...")

def clean_room():
    print("打扫房间开始...")
    # sleep 5 秒,默认以秒为单位
    time.sleep(5)
    print("打扫房间完成...")

if __name__ == "__main__":

    wash_clothes()
    clean_room()


'''
输出结果:

洗衣服开始...
洗衣服完成...
打扫房间开始...
打扫房间完成...

'''

运行程序可以发现程序从运行开始到结束,一共耗时 10 秒时间!注意观察输出日志:

  • 第一步:洗衣服开始;
  • 第二步:程序停止了 5 秒;
  • 第三步:洗衣服完成,打扫房间开始
  • 第四步:程序停止 5 秒;
  • 第五步:打扫房间结束,程序结束;

由此可见:多线程可以同时运行多个任务,效率远比单线程更高!

三.Python 线程传参

在上面的例子中,我们并没有为线程传递参数,如果在线程中需要传递参数怎么办呢?

threading.Thread 函数中有两个缺省参数 args 和 kwargs ,args 是元组类型,kwargs 是字典类型,缺省值默认为空,除此之外,其实还可以设置线程的名字等,其函数声明如下:

(ps:如果对缺省函数已经忘记的小伙伴请回到 Python 函数的声明和定义中关于缺省参数部分复习一下)

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:猿说编程
@Blog(个人博客地址): www.codersrc.com
@File:Python 线程创建和传参.py
@Time:2021/04/24 08:00
@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""

def __init__(self, group=None, target=None, name=None,
             args=(), kwargs=None, *, daemon=None):
    """This constructor should always be called with keyword arguments. Arguments are:

    *group* should be None; reserved for future extension when a ThreadGroup
    class is implemented.

    *target* is the callable object to be invoked by the run()
    method. Defaults to None, meaning nothing is called.

    *name* is the thread name. By default, a unique name is constructed of
    the form "Thread-N" where N is a small decimal number.

    *args* is the argument tuple for the target invocation. Defaults to ().

    *kwargs* is a dictionary of keyword arguments for the target
    invocation. Defaults to {}.

    If a subclass overrides the constructor, it must make sure to invoke
    the base class constructor (Thread.__init__()) before doing anything
    else to the thread.

    """

示例代码如下:

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:猿说编程
@Blog(个人博客地址): www.codersrc.com
@File:Python 线程创建和传参.py
@Time:2021/04/24 08:00
@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""

# 导入线程threading模块
import threading
# 导入内置模块time
import time

def wash_clothes(*args,**kargcs):
    print("wash_clothes:",args)
    print("wash_clothes:", kargcs)

def clean_room(*args,**kargcs):
    print("clean_room:",args)
    print("clean_room:", kargcs)

if __name__ == "__main__":
        # args 传递元组,可以同时传递多个数据
        # kwargs 传递字典,可以同时传递多个键值对
    t1 = threading.Thread(target=wash_clothes,args=(1,"猿说python"),kwargs={"a":1,"b":False})

        # args 传递元组,可以同时传递多个数据
        # kwargs 传递字典,可以同时传递多个键值对
    t2 = threading.Thread(target=clean_room,args=(2,False),kwargs={"c":0.2,"d":False})

    t1.start()
    t2.start()

四.Python 线程结束

值得思考的是:在上面这份代码中一共有几个线程呢?并非两个,一共是三个线程:

  • 线程一:__name__ == “__main__” 作为主线程;
  • 线程二:t1 作为子线程;
  • 线程三:t2 作为子线程;

注意:主程序会等待所有子程序结束之后才会结束!

五.Python 线程相关函数介绍

  • 1.threading.Thread — 创建线程并初始化线程,可以为线程传递参数 ;
  • 2.threading.enumerate — 返回一个包含正在运行的线程的 list;
  • 3.threading.activeCount — 返回正在运行的线程数量,与 len(threading.enumerate)有相同的结果;
  • 4.Thread.start — 启动线程 ;
  • 5.Thread.join — 阻塞函数,一直等到线程结束为止 ;
  • 6.Thread.isAlive — 返回线程是否活动的;
  • 7.Thread.getName — 返回线程名;
  • 8.Thread.setName — 设置线程名;
  • 9.Thread.setDaemon — 设置为后台线程,这里默认是 False,设置为 True 之后则主线程不会再等待子线程结束才结束,而是主线程结束意味程序退出,子线程也立即结束,注意调用时必须设置在 start 之前

简单的示例代码:

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:猿说编程
@Blog(个人博客地址): www.codersrc.com
@File:Python 线程创建和传参.py
@Time:2021/04/24 08:00
@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""

# 导入线程threading模块
import threading
# 导入内置模块time
import time

def wash_clothes(*args,**kargcs):
    time.sleep(2)
    print("wash_clothes:",args)
    time.sleep(2)
    print("wash_clothes:", kargcs)

def clean_room(*args,**kargcs):
    time.sleep(2)
    print("clean_room:",args)
    time.sleep(2)
    print("clean_room:", kargcs)

if __name__ == "__main__":

        # args 传递元组,可以同时传递多个数据
        # kwargs 传递字典,可以同时传递多个键值对
    t1 = threading.Thread(target=wash_clothes,args=(1,"猿说python"),kwargs={"a":1,"b":False})

    t2 = threading.Thread(target=clean_room,args=(2,False),kwargs={"c":0.2,"d":False})

    # setDaemon(True)意味着主线程退出,不管子线程执行到哪一步,子线程自动结束
    # t1.setDaemon(True)
    # t2.setDaemon(True)

    t1.start()
    t2.start()

    print("threading.enumerate():",threading.enumerate())
    print("threading.activeCount():", threading.activeCount())
    print("t1.isAlive():",t1.isAlive())
    print("t1.getName():", t1.getName())
    print("t2.isAlive():", t2.isAlive())
    t2.setName("my_custom_thread_2")
    print("t2.getName():", t2.getName())


'''
输出结果:

threading.enumerate(): [<_MainThread(MainThread, started 18388)>, <Thread(Thread-1, started 16740)>, <Thread(Thread-2, started 17888)>]
threading.activeCount(): 3
t1.isAlive(): True
t1.getName(): Thread-1
t2.isAlive(): True
t2.getName(): my_custom_thread_2
clean_room: (2, False)
wash_clothes: (1, '猿说python')
wash_clothes: {'a': 1, 'b': False}
clean_room: {'c': 0.2, 'd': False}

'''

六.Python 线程重点总结

1.默认主线程会等待所有子线程结束之后才会结束,主线程结束意味着程序退出;如果 setDaemon 设置为 True ,主线程则不会等待子线程,主线程结束,子线程自动结束;

2.threading 模块除了以上常用函数,还有互斥锁 Lock / 事件 Event / 信号量 Condition / 队列 Queue 等,由于篇幅有限,后面文章再一一讲解!!

七.猜你喜欢

  1. Python for 循环
  2. Python 字符串
  3. Python 列表 list
  4. Python 元组 tuple
  5. Python 字典 dict
  6. Python 条件推导式
  7. Python 列表推导式
  8. Python 字典推导式
  9. Python 函数声明和调用
  10. Python 不定长参数 *argc/**kargcs
  11. Python 匿名函数 lambda
  12. Python return 逻辑判断表达式
  13. Python 字符串/列表/元组/字典之间的相互转换
  14. Python 局部变量和全局变量
  15. Python type 函数和 isinstance 函数区别
  16. Python is 和 == 区别
  17. Python 可变数据类型和不可变数据类型
  18. Python 浅拷贝和深拷贝

未经允许不得转载:猿说编程 » Python 线程创建和传参

本文由博客 - 猿说编程 猿说编程 发布!