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

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

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

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

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

一.线程解释

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

二.线程创建和启动

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(个人博客地址): shuopython.com
@WeChat Official Account(微信公众号):猿说python
@Github:www.github.com @File:python_thread.py
@Time:2019/10/16 21:02 @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秒左右,示例代码如下:

# 导入内置模块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秒;
  • 第五步:打扫房间结束,程序结束;

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

三.线程传参

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

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

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

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. """

示例代码如下:

# 导入线程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__": t1 = threading.Thread(target=wash_clothes,
args=(1,"猿说python"), # args 传递元组,可以同时传递多个数据
kwargs={"a":1,"b":False}) # kwargs 传递字典,可以同时传递多个键值对 t2 = threading.Thread(target=clean_room,
args=(2,False), # args 传递元组,可以同时传递多个数据
kwargs={"c":0.2,"d":False}) # kwargs 传递字典,可以同时传递多个键值对 t1.start()
t2.start()

四.线程结束

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

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

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

五.相关函数介绍

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()之前;

简单的示例代码:

# 导入线程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__": t1 = threading.Thread(target=wash_clothes,
args=(1,"猿说python"), # args 传递元组,可以同时传递多个数据
kwargs={"a":1,"b":False}) # kwargs 传递字典,可以同时传递多个键值对 t2 = threading.Thread(target=clean_room,
args=(2,False), # args 传递元组,可以同时传递多个数据
kwargs={"c":0.2,"d":False}) # kwargs 传递字典,可以同时传递多个键值对 # 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}

六.重点总结

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

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

猜你喜欢:

1.python模块

2.python匿名函数

3.python不定长参数 *argc,**kargcs

4.python异常处理

转载请注明:猿说Python » python线程创建和传参

技术交流、商务合作请直接联系博主
扫码或搜索:猿说python
猿说python
微信公众号 扫一扫关注

python 线程创建和传参(28)的更多相关文章

  1. 『Python × C++』函数传参机制学习以及对比

    一.Python函数传参 在python中,函数传参实际上传入的是变量的别名,由于python内在的变量机制(名称和变量值相互独立),只要传入的变量不可变(tuple中的元素也要是不可变的才行),那么 ...

  2. 第24课 std::thread线程类及传参问题

    一. std::thread类 (一)thread类摘要及分析 class thread { // class for observing and managing threads public: c ...

  3. python字符串格式化--dict传参

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #python字符串格式化--dict传参 print "I'm %(name)s. I'm %(a ...

  4. # Python第十节 传参

    Python第十节 传参 一. 变量和变量名 首先说明变量名和变量的一点差异 例如: var = [1, 2, 3] `var = "Google" 调用变量var的时候, 既可以 ...

  5. python记录_day10 动态传参 命名空间 作用域

    一.动态传参 动态传参用到 *args 和 **kwargs ,*号表示接收位置参数,args是参数名:**表示接收关键字参数,kwargs是参数名 def chi(*food): print(foo ...

  6. python函数的动态传参.作用域与命名空间

    一.动态传参1.*表示动态传参. 可以接受所有的位置参数传参的时候自动的把实参打包成元组 交给形参 def chi(*food): print(food) chi() # 动态传参可以不传参数 chi ...

  7. python基础:函数传参、全局变量、局部变量、内置函数、匿名函数、递归、os模块、time模块

    ---恢复内容开始--- 一.函数相关: 1.1位置参数: ef hello(name,sex,county='china'): pass #hello('hh','nv') #位置参数.默认参数 1 ...

  8. python 传值引用和传参引用

    调用同事的函数,传入goods_list,获取商品信息,然后将商品信息与goods_list的信息进行匹配,合并. 但是同事返回数据的同时改变了我传入的参数,goods_list.相当于传参引用,也就 ...

  9. Java学习小结(1)-数组的创建与传参

    (一)数组的创建 数组的创建包括两部分:数组的申明与分配内存空间. int score[]=null; //申明一维数组 score=new int[3]; //分配长度为3的空间 数组的申明还有另外 ...

随机推荐

  1. 如何下载SlideShare的PPT:2种方法

    SlideShare中有很多不错的PPT,有时候确实想收藏怎么办,通常有2种方法: 1.SWF档案的PPT A. 打开PPT首页,按ctrl+U打开源码B. 找到类似以下语法的语句: <meta ...

  2. 【概率论】5-6:正态分布(The Normal Distributions Part III)

    title: [概率论]5-6:正态分布(The Normal Distributions Part III) categories: - Mathematic - Probability keywo ...

  3. Dns的作用

    DNS(Domain Name System,域名系统),万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串 DNS系统:通过 ...

  4. SQL 清理日志

    USE[master] GO ALTER DATABASE 要清理的数据库名称 SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE 要清理的数据库名称 ...

  5. Java Redis缓存穿透/缓存雪崩/缓存击穿,Redis分布式锁实现秒杀,限购等

    package com.example.redisdistlock.controller; import com.example.redisdistlock.util.RedisUtil; impor ...

  6. HikariCP 连接最快的连接池

    三点原因 1.字节码精简 2.自定义 FastList 代替ArrayList ;避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描: 3.优化代码和拦截 ...

  7. Python多线程与多进程详解

    进程,线程,协程https://blog.csdn.net/qq_23926575/article/details/76375337 多进程 https://www.cnblogs.com/lipij ...

  8. HearthBuddy的class276以及class247

    使用de4dot-cex反编译原版的hearthbuddy得到的 链接: https://pan.baidu.com/s/1hT79LpIjbyvODsjnkSe_5A 提取码: iemx class ...

  9. Type-C转接头 还是别用了,影响速率啊

      今天用Type-C转接USB头传照片真慢! 在数码配件领域,越是不起眼的小外设,隐藏其背后的猫腻和水分也就越多.就拿常见的Micro USB转USB Type-C转接头和TF转SD卡套而言,你觉得 ...

  10. Mysql中如何查看慢查询以及查看线程

    一.MySQL数据库有几个配置选项可以帮助我们及时捕获低效SQL语句 1,slow_query_log这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句. 2,long_query_time ...