Python之多线程退出与停止的一种实现思路

 更新时间:2024年02月18日 14:27:22   作者:InterStellar1145  
这篇文章主要介绍了Python之多线程退出与停止的一种实现思路,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Python多线程退出与停止

在使用多线程的过程中,我们知道,python的线程是没有stop/terminate方法的,也就是说它被启动后,你无法再主动去退出它,除非主进程退出了,注意,是主进程,不是线程的父进程.

一个比较合理的方式就是把原因需要放到threading.Thread的target中的线程函数,改写到一个继承类中

下面是一个实现例子

import threading
import time
import os
 
# 原本需要用来启动的无线循环的函数
def print_thread():
    pid = os.getpid()
    counts = 0
    while True:
        print(f'threading pid: {pid} ran: {counts:04d} s')
        counts += 1
        time.sleep(1)
 
# 把函数放到改写到类的run方法中,便可以通过调用类方法,实现线程的终止
class StoppableThread(threading.Thread):
 
    def __init__(self, daemon=None):
        super(StoppableThread, self).__init__(daemon=daemon)
        self.__is_running = True
        self.daemon = daemon
 
    def terminate(self):
        self.__is_running = False
 
    def run(self):
        pid = os.getpid()
        counts = 0
        while self.__is_running:
            print(f'threading running: {pid} ran: {counts:04d} s')
            counts += 1
            time.sleep(1)
 
 
def call_thread():
    thread = StoppableThread()
    thread.daemon = True
    thread.start()
 
    pid = os.getpid()
    counts = 0
    for i in range(5):
        print(f'0 call threading pid: {pid} ran: {counts:04d} s')
        counts += 2
        time.sleep(2)
    # 主动把线程退出
    thread.terminate()
 
 
if __name__ == '__main__':
    call_thread()
    print(f'==========call_thread finish===========')
    counts = 0
    for i in range(5):
        counts += 1
        time.sleep(1)
        print(f'main thread:{counts:04d} s')
 
 

python多线程实现

用于线程实现的Python模块

Python线程有时称为轻量级进程,因为线程比进程占用的内存少得多。 线程允许一次执行多个任务。

在Python中,以下两个模块在一个程序中实现线程 -

  • _thread模块
  • threading模块

这两个模块之间的主要区别在于_thread模块将线程视为一个函数,而threading模块将每个线程视为一个对象并以面向对象的方式实现它。

此外,_thread模块在低级线程中有效并且比threading模块具有更少的功能。

_thread 模块

在Python的早期版本中,拥有thread模块,但在相当长的一段时间里它已被视为“已弃用”。 鼓励用户改用threading模块。

因此,在Python 3中,thread模块不再可用。 它已被重命名为_thread,用于Python3中的向后不兼容。

为了在_thread模块的帮助下生成新的线程,我们需要调用它的start_new_thread方法。

这种方法的工作可以通过以下语法来理解 -

_thread.start_new_thread ( function, args[, kwargs] )

这里,

  • args是一个参数的元组
  • kwargs是关键字参数的可选字典

如果想在不传递参数的情况下调用函数,那么需要在args中使用一个空的参数元组。

此方法调用立即返回,子线程启动,并调用与传递的列表(如果有的话)args的函数。 线程在函数返回时终止。

示例

以下是使用_thread模块生成新线程的示例。在这里使用start_new_thread()方法

import _thread
import time

def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

try:
   _thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   _thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print ("Error: unable to start thread")
while 1:
   pass

在_thread模块的帮助下理解新线程的生成。

Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018

threading模块

threading模块以面向对象的方式实现,并将每个线程视为一个对象。

因此,它为线程提供了比_thread模块更强大,更高层次的支持。

该模块包含在Python 2.4中。

threading 模块中的其他方法

threading模块包含_thread模块的所有方法,但它也提供了其他方法。

其他方法如下:

  • threading.activeCount() - 此方法返回处于活动状态的线程对象的数量
  • threading.currentThread() - 此方法返回调用者线程控制中的线程对象数。
  • threading.enumerate() - 此方法返回当前活动的所有线程对象的列表。

为了实现线程,threading模块具有提供以下方法的Thread类

  • run() - run()方法是线程的入口点。
  • start() - start()方法通过调用run方法来启动线程。
  • join([time]) - join()等待线程终止。
  • isAlive() - isAlive()方法检查线程是否仍在执行。
  • getName() - getName()方法返回线程的名称。
  • setName() - setName()方法设置线程的名称。

如何使用 threading 模块创建线程?

在本节中,我们将学习如何使用threading模块创建线程。 按照以下步骤使用threading模块创建一个新线程 -

第1步 - 在这一步中,需要定义Thread类的新子类。

第2步 - 然后为了添加额外的参数,需要重写__init __(self [,args])方法。

第3步 - 在这一步中,需要重写run(self [,args])方法来实现线程在启动时应该执行的操作。

现在,在创建新的Thread子类后,可以创建它的一个实例,然后通过调用start()来启动一个新线程,start()又调用run()方法。

示例

下面这个例子演示如何使用threading模块生成一个新的线程

import threading
import time
exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      print_time(self.name, self.counter, 5)
      print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
Starting Thread-1
Starting Thread-2

执行上面示例代码,得到以下结果

Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread

带有线程状态的Python程序

有五种线程状态 - 新的,可运行,运行,等待和死亡。 在这五个中,我们将主要关注三个状态 - 运行,等待和死亡。

一个线程获取处于运行状态的资源,等待处于等待状态的资源; 如果执行和获取的资源的最终版本处于死亡状态。

下面的Python程序在start(),sleep()和join()方法的帮助下将分别显示线程是如何进入运行,等待和死亡状态的

  • 第1步 - 导入必要的模块,threading和time
import threading
import time
  • 第2步 - 定义一个函数,它将在创建线程时调用。
def thread_states():
   print("Thread entered in running state")
  • 第3步 - 使用time模块的sleep()方法让线程等待2秒钟。
time.sleep(2)
  • 第4步 - 现在,创建一个名为T1的线程,它接受上面定义的函数的参数。
T1 = threading.Thread(target=thread_states)
  • 第5步 - 现在,使用start()函数,可以开始启动线程。 它会产生这个信息,这个信息是在定义函数时设定的。
T1.start()
  • 第6步 - 现在,最后可以在完成执行后使用join()方法终止线程。
T1.join()

在Python中启动一个线程:

在python中,可以通过不同的方式启动一个新的线程,但其中最简单的一个就是将其定义为一个单一的函数。

在定义函数之后,可以将它作为新线程的目标。线程对象等等。

执行下面的Python代码来理解函数的工作原理 -

import threading
import time
import random
def Thread_execution(i):
   print("Execution of Thread {} started\n".format(i))
   sleepTime = random.randint(1,4)
   time.sleep(sleepTime)
   print("Execution of Thread {} finished".format(i))
for i in range(4):
   thread = threading.Thread(target=Thread_execution, args=(i,))
   thread.start()
   print("Active Threads:" , threading.enumerate()

执行上面代码,得到以下结果 -

Execution of Thread 0 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>]

Execution of Thread 1 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>]

Execution of Thread 2 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>]

Execution of Thread 3 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>,
      <Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished

在Python中启动一个线程:

在python中,可以通过不同的方式启动一个新的线程,但最简单的就是将其定义为一个单一的函数。

在定义函数之后,可以将它作为新线程的目标。线程对象等等。

执行下面的Python代码来理解函数的工作原理 -

import threading
import time

def nondaemonThread():
   print("starting my thread")
   time.sleep(8)
   print("ending my thread")
def daemonThread():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonThread = threading.Thread(target = nondaemonThread)
   daemonThread = threading.Thread(target = daemonThread)
   daemonThread.setDaemon(True)
   daemonThread.start()
   nondaemonThread.start(

在上面的代码中,有两个函数,分别是- nondaemonThread()和daemonThread()。

第一个函数打印其状态并在8秒后休眠,而deamonThread()函数每2秒无限期地打印出Hello。

我们可以通过以下输出来了解nondaemon和daemon线程之间的区别 -

Hello

starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • python+requests接口自动化框架的实现

    python+requests接口自动化框架的实现

    这篇文章主要介绍了python+requests接口自动化框架的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • python opencv对图像进行旋转且不裁剪图片的实现方法

    python opencv对图像进行旋转且不裁剪图片的实现方法

    今天小编就为大家分享一篇python opencv对图像进行旋转且不裁剪图片的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 关于adfuller函数返回值的参数说明与记录

    关于adfuller函数返回值的参数说明与记录

    这篇文章主要介绍了关于adfuller函数返回值的参数说明与记录,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Python OpenCV快速入门教程

    Python OpenCV快速入门教程

    这篇文章主要介绍了Python OpenCV快速入门教程,帮助大家更好的利用opencv处理图像,感兴趣的朋友可以了解下
    2021-04-04
  • 对python dataframe逻辑取值的方法详解

    对python dataframe逻辑取值的方法详解

    今天小编就为大家分享一篇对python dataframe逻辑取值的方法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-01-01
  • python常用的魔法方法(双下划线)

    python常用的魔法方法(双下划线)

    本文介绍一下python中常用的魔法方法以及面向对象中非常重要的单例模式。具有一定的参考价值,感兴趣的可以了解一下
    2021-09-09
  • virtualenv隔离Python环境的问题解析

    virtualenv隔离Python环境的问题解析

    virtualenv为应用提供了隔离的Python运行环境,解决了不同应用间多版本的冲突问题,这篇文章主要介绍了virtualenv隔离Python环境,需要的朋友可以参考下
    2022-06-06
  • Python动态导入模块和反射机制详解

    Python动态导入模块和反射机制详解

    这篇文章主要介绍了Python动态导入模块和反射机制详解,需要的朋友可以参考下
    2020-02-02
  • Java ExcutorService优雅关闭方式解析

    Java ExcutorService优雅关闭方式解析

    这篇文章主要介绍了Java ExcutorService优雅关闭方式解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • python 中的 return 解析

    python 中的 return 解析

    这篇文章主要介绍了python 中的 return 解析,return 语句用于退出函数,向调用方返回一个表达式。执行到 return 语句时,会退出函数,return 之后的语句不再执,下文下边就利用举例给大家讲解该内容得相关资料,需要的小伙伴可以参考一下
    2022-02-02

最新评论