Python多线程(基本使用、防止重复、杀死线程)

news/2024/7/2 23:48:20

目录

一、基本使用

1.方式一直接用

2.方式二创建类

二、守护进程

1.以第一种方式为例

2.以第二种方式为例

三、共享全局变量和互斥锁

四、防止重复

五、杀死线程

六、总结


由于Python中的多线程受GIL锁的限制,导致不能利用机器多核的特性,只能利用单核,是假的多线程。如果是cpu计算任务,建议使用multiprocessing处理,可以最大限度使用多核cpu。

多线程的应用场景为IO密集型任务,多线程是能够有效提升运行效率的,这是因为单线程下有IO操作时,会进行IO等待,这样会浪费等待的这段时间,而开启多线程能在线程A等待时,自动切换到线程B,可以减少不必要的时间浪费,从而能提升程序运行效率,但是也不是最好的选择,对于处理IO密集型任务,在Python还有更好的选择协程。

其实在平时,还有一种情况下会使用线程,就是需要执行无限任务时,这种线程应用不是很多。

一、基本使用

1.方式一直接用

import threading


def task():
    # 线程的任务
    print('111')


threading.Thread(target=task, name='dance').start()

2.方式二创建类

import threading


class MyThread(threading.Thread):

    def __init__(self):
        super().__init__()
        # self.num = num # 自定义参数

    def run(self):
        # 线程的任务
        print('111')
        return 'ok'


if __name__ == '__main__':
    my = MyThread()
    # 如果有参数
    # my = MyThread(num=1)
    my.start()

二、守护进程

在一个含有线程的python程序中,主线程的代码执行完毕,如果还有其他子线程还未执行完毕,那么主线程会等待子线程执行完毕之后,再结束;

如果有一个线程必须设置为无限循环,那么该线程不结束,意味着整个python程序就不能结束,那为了能够让python程序正常退出,将这类无限循环的线程设置为守护线程,当程序当中仅仅剩下守护线程时,python程序就能够正常退出,不必关心这类线程是否执行完毕。

1.以第一种方式为例

threading.Thread(target=task, name='task',daemon=True).start()
td = threading.Thread(target=task)
td.setName('task')
td.setDaemon(True)
td.start()

2.以第二种方式为例

    my = MyThread()
    # 如果有参数
    # my = MyThread(num=1)
    my.setName('task')
    my.setDaemon(True)
    my.start()

三、共享全局变量和互斥锁

建议参考:python多线程讲解_V-Sugar的博客-CSDN博客

"""多线程共享全局变量"""
import threading
import time


g_num = 100  # 这个要使用global
list = [1,2]  # 这个在函数中执行的时候要是不改变他的指向就不需要使用global


def test1():
    """改变全局变量"""
    global g_num
    g_num += 1
    list.append(1)
    print('-----test1----g_num:%d----' % g_num)
    print(f'list初始:[1,2]检查是否可以在不使用global的情况下使用全局变量:{list}')


def test2():
    """打印全局变量g_num,如果共享则打印的全局变量为101"""
    global g_num
    print('----test2----g_num:%d----' % g_num)
    print(f'----test2----list:{list}----')


def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)

    t1.start()
    time.sleep(1)  # 确保test1先执行
    t2.start()
    time.sleep(1)

    print('----in main g_num = %d----' % g_num)


if __name__ == '__main__':
    main()

四、防止重复

以第一种方式启动为例,具体代码如下:

import threading


def task():
    # 线程的任务
    print('111')


def repeat_thread_detection(t_name):
    # 判断 tName线程是否处于活动状态
    for item in threading.enumerate():
        print('线程列表', item)
        if t_name == item.name:  # 如果名字相同,说明tName线程在活动的线程列表里面
            return True
    return False


if not repeat_thread_detection('task'):
    threading.Thread(target=task, name='task').start()
else:
    print('task线程还处于活动状态,请勿启动新的实例')

五、杀死线程

我们使用线程后,很多时候线程任务完成就会随着主线程结束。但是如果我们运行的线程是一个不会结束的线程,在调试使用过程中多次执行,这时候经常会发现线程的结果还是上一次的或者打印出了两次或多次的结果。这是因为不死线程在再次执行后,前一次的线程没有被新执行的任务取代,而是又新建立了一个进程,在新的进程中开启了新的线程。此时,多个线程在同时运行。

此处以第二种使用方式为例

import os
import threading


def kill(pid):
    # 本函数用于中止传入pid所对应的进程
    if os.name == 'nt':
        # Windows系统
        cmd = 'taskkill /pid ' + str(pid) + ' /f'
        try:
            os.system(cmd)
            print(pid, 'killed')
        except Exception as e:
            print(e)
    elif os.name == 'posix':
        # Linux系统
        cmd = 'kill ' + str(pid)
        try:
            os.system(cmd)
            print(pid, 'killed')
        except Exception as e:
            print(e)
    else:
        print('Undefined os.name')


class MyThread(threading.Thread):

    def __init__(self):
        super().__init__()
        # self.num = num # 自定义参数

    def run(self):
        # 线程的任务
        print('111')
        return 'ok'


if __name__ == '__main__':

    # 1.读取上次保存的pid
    f1 = open(file='feishu_pid.txt', mode='r')
    pid = f1.read()
    f1.close()
    # 2.如果存在杀死上一次的进程
    print('上一次进程', pid)
    if pid:
        # 调用kill函数,终止进程
        kill(pid=pid)

    # 3.获取当前进程的pid
    pid = os.getpid()
    print('当前进程的pid: ', pid)

    # 4.将pid写入本地文件,供下次调用
    f2 = open(file='feishu_pid.txt', mode='w')
    f2.write(pid.__str__())
    f2.close()
    # 5.开启新的线程
    my = MyThread()
    # 如果有参数
    # my = MyThread(num=1)
    my.start()

六、总结

  1. 线程是操作系统调度的单位
  2. 线程在不考虑GIL的情况及下切换时需要的资源比较小
  3. 多线程中:如果主线程结束了所有的线程都会结束

http://lihuaxi.xjx100.cn/news/3645.html

相关文章

风控违约场景如何预测,来看看这份常见的三种模型实现算法对比

在机器学习算法中,树模型在风控、营销等实际业务场景应用中始终备受青睐。其中对于GBDT集成学习树模型,我们是非常熟悉的,而且在此基础上发展而来的XGBoost、LightGBM更是我们日常建模场景中经常接触到的,可以称为是Boosting算法体…

Java毕设项目——智能仓储系统(java+SSM+Maven+Mysql+Jsp)

文末获取源码 开发语言:Java 框架:SSM 技术:Jsp JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包&#xff1a…

计算机毕业设计Java演出票在线预定网站系统(源码+系统+mysql数据库+Lw文档)

计算机毕业设计Java演出票在线预定网站系统(源码系统mysql数据库Lw文档) 计算机毕业设计Java演出票在线预定网站系统(源码系统mysql数据库Lw文档)本源码技术栈: 项目架构:B/S架构 开发语言:Ja…

经验分享:产品经理面试的5大技巧

​感谢Andy 老师给这个机会给大家分享一下我的一些面试心得,做了一个简单的总结给大家说一下。 今天的分享内容一共有6方面: 1、个人职业的总结 2、面试前学习的内容 3、我们如何去寻找面试机会 4、我们该如何准备面试 5、面试过程中遇到的常见问题…

postgresSQL多种字符串分割及查询汇总

目录 表及数据准备 SPLIT_PART函数应用及说明 string_to_array函数应用及说明 基于指定规则查询该列所有 按需分割后产生的字符串单独判断 按需分割后产生的字符串及其它列混合查询 以按需分割查询为条件查询其它列 array_length函数应用及说明 表及数据准备 测试表 …

艾美捷Abnova MYOC (人)抗体对说明书

MYOC 编码蛋白质肌纤蛋白,据信它在细胞骨架功能中起作用。MYOC 在包括小梁网在内的许多眼组织中表达,并被揭示为小梁网糖皮质激素诱导反应蛋白 (TIGR)。小梁网是调节眼压所必需的特殊眼组织,MYOC 的突变已被确定为遗传性青少年型开角型青光眼…

使用Softing为西门子工业边缘开发的edgePlug软件简化了设备与应用程序的连接

一 为西门子工业边缘应用轻松提供控制器数据 作为西门子工业边缘市场的一部分,Softing edgePlug软件产品通过西门子工业边缘(一个由边缘设备、应用程序和设备管理组成的开放、即用型边缘计算平台)将西门子PLC连接到应用程序。 这意味着&…

c语言基础学习笔记(三):while循环

文章目录while循环四位数以下判断数的位数程序示例while循环数位数的算法do-while循环do-while循环实现数位数计算 log2log_2log2​X 的程序示例倒计时循环程序示例猜数游戏程序示例while循环 四位数以下判断数的位数程序示例 人可以一眼看出这是几位数,但计算机不…