改变 Python 中线程执行顺序的方法

一、主线程会等待所有的子线程结束后才结束

首先我看下最普通情况下,主线程和子线程的情况。

import threading
from time import sleep, ctime

def sing():
 for i in range(3):
  print("正在唱歌...%d" % i)
  sleep(1)

def dance():
 for i in range(3):
  print("正在跳舞...%d" % i)
  sleep(1)

if __name__ == '__main__':
 print('---开始---:%s' % ctime())

 t1 = threading.Thread(target=sing)
 t2 = threading.Thread(target=dance)

 t1.start()
 t2.start()

 print('---结束---:%s' % ctime())

运行结果:

最后一行打印的代码就算在一开始运行了,程序也不会结束。

只有等待所有的子线程(sing 和 dance)都执行完毕,主线程才会结束,即程序结束。

二、默认状态下,多线程的执行顺序是不确定的

我们先来看一段代码:

import threading
import time

class MyThread(threading.Thread):
 def run(self):
  for i in range(3):
   time.sleep(1)
   msg = "I'm "+self.name+' @ '+str(i)
   print(msg)

def test():
 for i in range(5):
  t = MyThread()
  t.start()

if __name__ == '__main__':
 test()

运行结果:

I'm Thread-1 @ 0
I'm Thread-2 @ 0
I'm Thread-3 @ 0
I'm Thread-4 @ 0
I'm Thread-5 @ 0
I'm Thread-1 @ 1
I'm Thread-3 @ 1
I'm Thread-2 @ 1
I'm Thread-4 @ 1
I'm Thread-5 @ 1
I'm Thread-1 @ 2
I'm Thread-3 @ 2
I'm Thread-2 @ 2
I'm Thread-4 @ 2
I'm Thread-5 @ 2

每次的运行结果可能都不一样,但大体差不多。

说明:

从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。

当执行到 sleep 语句时,线程将被阻塞,到 sleep 结束后,线程进入就绪状态,等待调度,而线程调度将自行选择一个线程执行。

上面的代码中只能保证每个线程都运行完整个 run 函数,但是线程的启动顺序、run 函数中每次循环的执行顺序都不能确定。

总结

每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的 name,但是 python 会自动为线程指定一个名字。

当线程的 run() 方法结束时该线程完成。

无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

三、Python daemon 守护线程详解

当程序中拥有多个线程时,主线程执行结束并不会影响子线程继续执行。

换句话说,只有程序中所有线程全部执行完毕后,程序才算真正结束。

Python 还支持创建另一种线程,称为守护线程(或后台线程)。

此类线程的特点是,当程序中主线程及所有非守护线程执行结束时,未执行完毕的守护线程也会随之消亡,程序将结束运行。

守护线程本质也是线程,因此其创建方式和普通线程一样,唯一不同之处在于,将普通线程设为守护线程,需通过线程对象调用其 damon 属性,将该属性的值改为 True。

注意:线程对象调用 daemon 属性必须在调用 start() 方法之前,否则 Python 解释器将报 RuntimeError 错误。

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + "," + str(i))

def main():
 t1 = threading.Thread(target=action, args=(10,))
 # 设置子线程为守护进程
 t1.daemon = True
 t1.start()

 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

运行结果:

Thread-1,0
MainThread,0
MainThread,1
MainThread,2

程序中,子线程里的程序就循环了一次,接着主线程执行完后,子线程就不打印信息了。

由于该程序中除了守护线程就只有主线程,因此只要主线程执行结束,则守护线程也随之消亡。

四、控制线程执行顺序

通过前面的学习我们知道,主线程和子线程会轮流获得 CPU 的资源。

但有时候,我们想让某个子线程先执行,然后再让主线程执行代码,该如何实现呢?

很简单,通过调用线程对象的 join() 方法即可。

join() 方法的功能是在程序指定位置,优先让该方法的调用者使用 CPU 资源。

该方法的语法格式如下:

thread.join( [timeout] )

timeout 参数作为可选参数,其功能是指定 thread 线程最多可以霸占 CPU 资源的时间(以秒为单位)。

如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放 CPU 资源。

我们仍旧拿上面的例子来举例:

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + "," + str(i))

def main():
 t1 = threading.Thread(target=action, args=(10,))
 # 设置子线程为守护进程
 t1.daemon = True
 t1.start()
 t1.join()
 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

我们在子线程调用的后面,添加了 t1.join()。

运行结果:

Thread-1,0
Thread-1,1
Thread-1,2
Thread-1,3
Thread-1,4
Thread-1,5
Thread-1,6
Thread-1,7
Thread-1,8
Thread-1,9
MainThread,0
MainThread,1
MainThread,2

上面的例子中,t1 线程调用了 join() 方法,并且没有指定具体的 timeout 参数值。

这意味着如果程序想继续往下执行,必须先执行完 t1 子线程。

以上就是改变 Python 中线程的执行顺序的方法的详细内容,更多关于改变 Python 中线程的执行顺序的资料请关注我们其它相关文章!

(0)

相关推荐

  • python实现多线程的方式及多条命令并发执行

    一.概念介绍 Thread 是threading模块中最重要的类之一,可以使用它来创建线程.有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法:另一种是创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入. Thread模块是比较底层的模块,Threading模块是对Thread做了一些包装的,可以更加方便的被使用. 另外在工作时,有时需要让多条命令并发的执行, 而不是顺序执行. 二.代码样例 #!/usr/bin/py

  • python多线程方式执行多个bat代码

    python多线程方式执行多个bat的代码,感兴趣的朋友可以参考下. import threading from win32api import * class MyThread(threading.Thread): def __init__(self, bat_path, **kwargs): threading.Thread.__init__(self, **kwargs) self.bat_path = bat_path def run(self): ShellExecute(0, Non

  • python多线程实现同时执行两个while循环的操作

    如果想同时执行两个while True循环,可以使用多线程threading来实现. 完整代码 #coding=gbk from time import sleep, ctime import threading def muisc(func): while True: print 'Start playing: %s! %s' %(func,ctime()) sleep(2) def move(func): while True: print 'Start playing: %s! %s' %

  • 详解Python 多线程 Timer定时器/延迟执行、Event事件

    Timer继承子Thread类,是Thread的子类,也是线程类,具有线程的能力和特征.这个类用来定义多久执行一个函数. 它的实例是能够延迟执行目标函数的线程,在真正执行目标函数之前,都可以cancel它. Timer源码: class Timer(Thread): def __init__(self, interval, function, args=None, kwargs=None): Thread.__init__(self) self.interval = interval self.

  • python 实现两个线程交替执行

    我就废话不多说,直接看代码吧! import threading import time def a(): while True: lockb.acquire() print('a') locka.release() time.sleep(0.5) def b(): while True: locka.acquire() print('b') lockb.release() time.sleep(0.5) if __name__ == "__main__": locka = threa

  • 浅谈Python3多线程之间的执行顺序问题

    一个多线程的题:定义三个线程ID分别为ABC,每个线程打印10遍自己的线程ID,按ABCABC--的顺序进行打印输出. 我的解法: from threading import Thread, Lock # 由_acquire解锁执行后释放_release锁 def _print(_id: str, _acquire: Lock, _release: Lock) -> None: for i in range(10): _acquire.acquire() print(f"id:{_id}&

  • python使用装饰器和线程限制函数执行时间的方法

    本文实例讲述了python使用装饰器和线程限制函数执行时间的方法.分享给大家供大家参考.具体分析如下: 很多时候函数内部包含了一些不可预知的事情,比如调用其它软件,从网络抓取信息,可能某个函数会卡在某个地方不动态,这段代码可以用来限制函数的执行时间,只需要在函数的上方添加一个装饰器,timelimited(2)就可以限定函数必须在2秒内执行完成,如果执行完成则返回函数正常的返回值,如果执行超时则会抛出错误信息. # -*- coding: utf-8 -*- from threading imp

  • 使用Python paramiko模块利用多线程实现ssh并发执行操作

    1.paramiko概述 ssh是一个协议,OpenSSH是其中一个开源实现,paramiko是Python的一个库,实现了SSHv2协议(底层使用cryptography). 有了Paramiko以后,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作. 由于paramiko属于第三方库,所以需要使用如下命令先行安装 2.安装paramiko pip install paramiko 3.常用方法 connect():实现远程服务器的

  • 改变 Python 中线程执行顺序的方法

    一.主线程会等待所有的子线程结束后才结束 首先我看下最普通情况下,主线程和子线程的情况. import threading from time import sleep, ctime def sing(): for i in range(3): print("正在唱歌...%d" % i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d" % i) sleep(1) if __name__ == '

  • 在python中按照特定顺序访问字典的方法详解

    最近使用python写一些东西,在参考资料的时候发现字典是没有顺序的,那么怎么样按照一定顺序访问字典呐,我找到了一个小方法: 假设一个字典是: D = {'a': '1', 'b': '2', 'c': '3'} 如果我们要按照a, b, c的顺序访问字典,可以借助一个列表,比如说: L = list(D.keys()) L.sort() for key in L: print(key, 'is' D[key]) 输出为: a is 1 b is 2 c is 3 需要倒序的话只需使用倒序函数排

  • 在python中以相同顺序shuffle两个list的方法

    通常做机器学习问题时,需要准备训练数据,通常会把样本数据和标签存放于2个list中,比如train_x = [x1,x2,...,xN][x1,x2,...,xN],train_y = [y1,y2,...,yN][y1,y2,...,yN]. 有时候是需要将数据shuffle后再做处理的(比如,批量梯度下降算法,需要数据是打乱的). 这时就需要以相同的顺序打乱两个list,那么在python中如何实现呢?可以通过设置相同的随机种子,再shuffle的方式来实现. 代码如下: import ra

  • Shell脚本中多命令逻辑执行顺序的方法详解

    Linux中可以使用分号";".双and号"&&"和双竖线"||"来连接多个命令.单"&"符号也算命令连接符号,只不过它是将其前面的命令放入后台执行,所以可以变相地实现命令并行执行. 1.分号";" command1 ; command2 命令之间没有逻辑关系.分号连接的命令会按照顺序从前向后依次执行,但分号两端的命令之间没有任何逻辑关系,所有写出来的命令最终都会被执行,即使分号前面

  • Python中线程threading.Thread的使用详解

    目录 1. 线程的概念 2. threading.thread()的简单使用 2.1 添加线程可以是程序运行更快 2.2 主线程会等待所有的子线程结束后才结束 3.查看线程数量 4.线程参数及顺序 4.1 传递参数的方法 4.2 线程的执行顺序 5. 守护线程 1. 线程的概念 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成.另外,线程是进程中的一个实体,是被系统独立调度和

  • python中shell执行知识点

    os.system system方法会创建子进程运行外部程序,方法只返回外部程序的运行结果.这个方法比较适用于外部程序没有输出结果的情况. import os os.system('ls') commands.getstatusoutput 使用commands模块的getoutput方法,这种方法同popend的区别在于popen返回的是一个文件句柄,而本方法将外部程序的输出结果当作字符串返回,很多情况下用起来要更方便些. 主要方法: commands.getstatusoutput(cmd)

  • python中_del_还原数据的方法

    在数据存储过多时,我们会选择清除,不过有时候也需要找回一些我们之前删掉的数据.有的小伙伴可能会使用不同的方法分别完成,那么今天小编带来的_del_方法既能满足数据的清除,同时也可以把删除的数据重新找回来.考虑到大家对数据还原的方法比较急缺,接下来我们就_del_如何还原数据的方法进行讲解. _del_在对象销毁时被调用,往往用于清除数据或还原环境等操作,比如在类中的其他普通方法中实现了插入数据库的语句,当对象被销毁时我们需要将数据还原,那么这时可以在__del__方法中实现还原数据库数据的功能.

  • Python中线程锁的使用介绍

    目录 前言 方式一:使用try/finally,确保锁肯定会被释放. 方式二:with语句避免使用try/finally. 总结 前言 当有多个线程,且它们同时访问同一资源时,需要考虑如何避免线程冲突.解决办法是使用线程锁.锁由Python的threading模块提供,并且它最多被一个线程所持有.当一个线程试图获取一个已经锁在资源上的锁时,该线程通常会暂停运行,直到这个锁被释放.看看下面的不具备锁功能的例子: #!/usr/bin/env python3 # -*- coding:utf-8 -

  • 深入了解Python 中线程和进程区别

    目录 一.什么是进程/线程 1.引论 2.线程 3.进程 4.区别 5.使用 二.多线程使用 1.常用方法 2.常用参数 3.多线程的应用 3.1重写线程法 3.2直接调用法 4.线程间数据的共享 三.多进程使用 1.简介 2.应用 2.1重写进程法 2.2直接调用法 3.进程之间的数据共享 3.1Lock方法 3.2Manager方法 四.池并发 1.语法 2.获取CPU数量 3.线程池 3.进程池 一. 什么是进程 / 线程 1. 引论 众所周知,CPU是计算机的核心,它承担了所有的计算任务

  • Python中range函数的使用方法

    目录 1.range()函数是什么? 2.语法格式 3.报错问题 4.range()函数需要注意的 5.range对象是不可变序列 6.range函数实现逆序遍历 7.与列表list的使用 8.关于range函数小结 前言: 本篇基于Python3环境,Python2环境下的range会有所不同,但并不影响我们使用. 1.range()函数是什么? range()函数是python的内置函数,它能返回一系列连续添加的整数,能够生成一个列表对象. 大多数时常出如今for循环中,在for循环中可做为

随机推荐