• 1
  • 0
分享

1.单线程执行

Python的内置模块提供了两个线程模块:threading 和thread。

    thread:是原生的

    threading:是扩展的

用法:

    变量 = threading.Thread(target = 执行函数)

    变量.strart()

代码示例

# -*- coding:utf-8 -*-
# @Time   : 2020-06-08
# @Author : Carl_奕然

import threading
#自定义test函数
def test():
    print("test threading")
    
#创建一个单线程,来执行test()函数
t = threading.Thread(target= test)
t.start()

运行结果

test threading

2、多线程执行

单线程已经会使用,那么多线程还会远吗?
多线程只需要通过循环创建多个线程,并通过循环启动执行就可以了。
我们来看个例子,为了更直观,我把打印的内容修改成打印时间:

代码示例:

# -*- coding:utf-8 -*-
# @Time   : 2020-06-08
# @Author : Carl_奕然

import threading
from datetime import *

#自定义test函数
def test():
    now = datetime.now()  #获取当前时间
    print("打印多线程执行时间:",now)
#自定义thr()函数,来执行多线程
def thr():
    threads = []  #自定义一个空的数组,用来存放线程组
    for i in range(10):  #设置循环10次
        t = threading.Thread(target=test)
        threads.append(t)  #把创建的的线程t,装到threads 数组中
    #启动线程
    for t in threads: 
        t.start()
#执行thr()函数进行多并发
if __name__ == "__main__"   :
    thr()

运行结果

2.png

我们可以看到,我循环执行了10次,这时间相差的太小了,可以忽略不计。

如果,我设置1000次,10000次的话,如果还是这样写,是不是需要等待很长时间?服务器的压力会不会增加?资源消耗会不会增加?

那如何优化呢?

来看这个例子:

我们执行1000次并发,把这1000次拆成50个线程,每个线程循环20次,这样是不是就会快很多?

我们来看看执行效率

3.png

修改代码

# -*- coding:utf-8 -*-
# @Time   : 2020-06-08
# @Author : Carl_奕然

import threading
from datetime import *

#自定义test函数
def test():
    now = datetime.now()  #获取当前时间
    print("打印多线程执行时间:",now)
#设置50个线程
def looptest():
    for i in range(50):
        test()

#自定义thr()函数,来执行多线程
def thr():
    threads = []  #自定义一个空的数组,用来存放线程组
    for i in range(20):  #设置循环10次
        t = threading.Thread(target=test)
        threads.append(t)  #把创建的的线程t,装到threads 数组中
    #启动线程
    for t in threads:
        t.start()
#执行thr()函数进行多并发
if __name__ == "__main__"   :
    thr()

运行结果:

4.png

是不是快很多了。

3.守护线程

在了解守护线程之前,先来了解下主线程与子线程的区别。

主线程与子线程的区别:

每个线程都有一个唯一标示符,来区分线程中的主次关系的说法。

线程唯一标示符:Thread.CurrentThread.ManagedThreadID;

    ・UI界面和Main函数均为主线程。

    ・被Thread包含的“方法体”或者“委托”均为子线程。

    ・委托可以包含多个方法体,利用this.Invoke去执行。

    ・也可以定义多种方法体,放在Thread里面去执行。则此方法・体均为子线程。注意如果要修改UI界面的显示。则需要使用this.Invoke,否则会报异常。

    ・Main函数为主线程,id标示符与UI界面主线程相等。

对照上面的代码,main()就是主线程,thr()就是子线程。

>>即先启动main(),然后执行thr()启动子线程。

那么,什么是守护线程呢?

>>即当主线程执行完毕后,所有的子线程也被关闭(无论子线程是否执行完成)。默认是不设置守护线程的。

但是我们又为什么要用守护线程呢?

>>说的直接,就是为了防止死循环。

>>因为一个死循环如果不手动停止,我们都知道会一直的循环下去,直到资源耗尽。

那么守护线程的用法是什么呢?

>>setDaemon():默认是 False, 需要改成True才能启用。

代码示例:

# -*- coding:utf-8 -*-
# @Time   : 2020-06-08
# @Author : Carl_奕然

import threading
from datetime import *

#自定义test函数
def test():
    x=0
    while (x ==0):    #修改成死循环
        print(datetime.now())
#自定义thr()函数,来执行多线程
def thr():
    threads = []  #自定义一个空的数组,用来存放线程组
    for i in range(20):  #设置循环10次
        t = threading.Thread(target=test)
        threads.append(t)  #把创建的的线程t,装到threads 数组中
        t.setDaemon(True) # 设置守护线程
    #启动线程
    for t in threads:
        t.start()
#执行thr()函数进行多并发
if __name__ == "__main__"   :
    thr()
    print("守护线程功能启用,end")

运行结果:

20200608160659208.png

4.阻塞线程

强制程序停止,除了运用守护线程,还可以用到 阻塞线程,

如果说前者是强硬派,那么后者就属于温柔派。

那么我们再来看看阻塞线程;

阻塞线程:通过子线程 join()方法来阻塞线程,

让主线程等待子线程完成之后再往下执行,

等主线程执行完毕后在挂你吧所有子线程。

代码示例:

# -*- coding:utf-8 -*-
# @Time   : 2020-06-08
# @Author : Carl_奕然

import threading
from datetime import *

def test():
    x =0
    while(x ==0):
        print(datetime.now())

def thr():
    threads = []
    for i in range(10):
        t = threading.Thread(target=test)
        threads.append(t)
        t.setDaemon(True)

    for t in  threads:
        t.start()
for t in threads:
    t.join()

if __name__ == "__main__":
    thr()
    print("阻塞线程功能启动,end")

这段代码,是不是让你有一种想喝(灭)水(火)的冲动??

那就对了,因为不能停止吗~ ~ ~ ~

那,这和什么都不设置不是一样???

莫着急,其实还是有一点区别的:

    >>什么都不设置的情况下主线程是执行完的,仅等待子线程执行完,所以会打印end信息

    >>而两个都设置的情况下,主线程会因为等待子线程结束而不往下执行,主线程无法执行完成,所以也就是无法关闭子线程,不会打印end信息

对于死循环这种情况,可以在join()设置timeout来控制

即,我们来设置个2秒钟,

    for t in threads:
        t.join(2)

但是你执行之后,会发现,为啥不是2秒停止,而是20秒才停止,是因为我们执行了10个线程, 而每个线程执行2秒,故10个线程timeout时间就是20秒。
是不是不太讲究,哎~~没办法,就顺了吧!!

    那么阻塞线程的意义是啥呢?
        >>阻塞线程的意义在于控制子线程与主线程的执行顺序!




  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   Google正在升级 Gmail 中的Gemini写作工具,以帮助你润色已经写好的草稿。Google在一篇博文中说,现在,在其他由 Gemini 支持的"帮我写"选项(如正式化和详细化)中,你可以点击"润色"来润色你的电子邮件。  该公司还在 Android 和 iOS 上的电子邮件正文中添加了快捷方式,让人更清楚地知道有人工智能写作工具可以使用。  Google One AI 高级账户的付费用户或Google工作空间Gemini插件的付费用户可以使用这些工具。如果你是这样的人,当你打开一个空草稿时,你会看到一个"帮我写"的快捷方...
            0 0 299
            分享
          •   经常都有人问我软件测试前景怎么样,每年也都帮助很多朋友做职业分析和学习规划,也很欣慰能够通过自己的努力帮到一些人进入到大厂。  2024年软件测试行业的发展现状以及未来的前景趋势  最近很多测试人在找工作的时候,明显的会发现功能测试很难找到工作,即使有,也是外包,甚至外包都要求会性能或者自动化测试。所以对于纯手工测试,不好找工作的情况是真实存在的。  另外就是技术的发展,CI/CD/DevOps的项目管理迭代的方法论的流行加大了测试压力。你要是刚开始进入这个行业,可能认为测试就是找bug,但是测试工程师的核心是质量保证。短时间迭代越来越快的节奏下,其实已经没有办法再靠人力去支撑了,到时候必...
            0 0 470
            分享
          •   自我看来:  软件测试这个行业发展得比较稳定,疫情虽然也波及到了互联网的道路上,但软件企业要靠软件产品的质量去占领市场这一点始终没有改变,“没有开发这个产品都不可能做出来,而没有测试,产品的bug可能比较多而已“这里论断走远了。换位思考,软件测试也会成为一个软件企业的生存命脉。用户以及你我都不愿意使用体验不好的产品。所以测试这关过不了,产品做出来也得不到在市场上生长的机会。So软件测试会越来越受到重视。  基于以上一点。我不否认没有前瞻性的公司以往对待测试员的不重视。所以面对软件与技术的更新换代,部分测试人员因为知识不成体系或者学得不够扎实,导致技术水平不过关,难当大任。而企业更需要技术扎...
            0 0 631
            分享
          • 前言例如:测试工程师面试题目1、软件的生命周期有哪些阶段?① 需求阶段分析和学习阶段,团队去查看这个需求是不是可测的。② 计划阶段辨别出哪些活动和资源和测试的目标时匹配的,辨别并追踪这些测试的指标、计划。③ 分析阶段通过需求文档等条件辨别测试条件,追溯到需求。④ 设计阶段概述测试条件;获取测试数据;搭建环境;跟踪测试指标。⑤ 编码阶段创建详细的测试用例,进行编码。⑥ 运行和维护阶段⑦ 总结阶段检验完成度和用户满意度。2、测试的整个流程有哪些① 需求评审阅读需求,理解需求,查看是否有不符合逻辑的需求,明确测试周期。② 测试计划根据项目计划和开发人员的时候指定测试计划,包含测试内容、测试规划、测试...
            1 1 3074
            分享
          •   最近,项目上出于系统性稳定性、减少测试工作量考虑,打算在 Web 前端引入 BDD。由于上一个项目写了一定的 Cucumber 代码(BDD 测试框架之一),这个框架选型的责任便落到了我的肩膀上了。  在我们进行框架选型的时候,着重考虑了一个因素:测试实现脚本是由开发人员编写的,因此最好寻找 JavaScript 支持的框架。在搜索了一天后,选择了三个框架 Cucumber、Robot、Gauge。以下是上述的三个框架入选的原因:  Cucumber,团队的开发人员有一些有相关的开发经验、支持 JavaScript。  Robot Framework,测试人员接受过相关的培训、不支持 Ja...
            0 0 563
            分享
      • 51testing软件测试圈微信