首页 > 编程语言 >Python多任务编程的三种方式

Python多任务编程的三种方式

时间:2024-07-19 20:26:33浏览次数:16  
标签:__ thread Python 编程 start num 线程 多任务 def

计算机的设计就是为了帮助人类或者模仿人类的某些行为。

生活中的多任务:人可以一边唱歌,一边跳舞;人开车的时候是通过手、脚和眼睛共同配合来驾驶一辆车。

多任务编程就是这样一个鲜明的例子,计算机也可以实现多任务编程:比如一边听歌一边玩游戏、打开浏览器上网同时能登录微信、QQ等聊天工具。

那么Python的多任务有哪些方式呢?

Python多任务编程的三种方式

  • 多线程
  • 多进程
  • 协程

今天我们先来聊一聊Python的多线程编程。

线程

有两种不同类型的线程:

  • 内核线程
  • 用户空间线程或用户线程

内核线程是操作系统的一部分,而用户空间线程未在内核中实现,关于线程和进程的更多概念请点此处

Python中的线程

Python中有两个关于线程的模块:

  • thread
  • threading

Ps:一直以来,​​thread​​​模块一直都不被推荐使用,鼓励推荐使用​​threading​​​模块,所以在Python3中的向后兼容,​​thread​​​模块被重命名为​​_thread​

>>> import thread
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import thread
ModuleNotFoundError: No module named 'thread'
>>> import _thread
>>>

threading 模块自 Python 1.5.1(1998 年)就已存在,不过有些人仍然继续使用旧的 thread 模块。Python 3 把 thread 模块重命名为 _thread,以此强调这是低层实现,不应该在应用代码中使用。

thread模块

可以使用​​Thread​​​模块在单独的线程中执行功能。为此,我们可以使用函数​​thread.start_new_thread​​:

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

此方法可以快速有效地在Linux和Windows中创建新线程。这个方法先接收一个函数对象(或其他可调用对象)和一个参数元组,然后开启新线程来执行所传入的函数对象及其传入的参数。

import _thread
def child(tid):
    print("Hello from thread", tid)
def parent():
    i = 0
    while True:
        i += 1
        _thread.start_new_thread(child, (i,))  # 创建线程的调用
            
        if input() == 'q':
            break
parent()

我们运行上段程序,然后只要不在控制台输入q,就能看到不断有新的线程创建和退出。当主线程退出时,整个线程就随之退出了。

Hello from thread 1

Hello from thread 2

Hello from thread 3

Hello from thread 4

Hello from thread 5
q

多线程唱歌跳舞

假如我们让电脑????模拟唱跳,就需要启动两个线程,同时利用time.sleep避免主线程过早退出,但是线程输出可能随机。

from _thread import start_new_thread
import time
def sing():
    for i in range(3):
        print("I'm singing 难忘今宵")
        time.sleep(2)
def dance():
    for i in range(3):
        print("I'm dancing")
        time.sleep(2)
def main():
    start_new_thread(sing, ())
    start_new_thread(dance, ())
    time.sleep(8)
    print('Main thread exiting...')
if __name__ == '__main__':
    main()

如上代码,我们需要唱3遍“难忘今宵”,同时跳三遍伴舞。​​time.sleep(8)​​​避免主线程过早退出导致新建的​​sing​​​和​​dance​​线程提前退出,所以输出结果可能(每次执行的输出可能不一样):

I'm singing 难忘今宵
I'm dancing
I'm dancing
I'm singing 难忘今宵
I'm dancing
I'm singing 难忘今宵
Main thread exiting...

输出结果的不规律是因为所有的线程的函数调用都在同一进程中运行,它们共享一个标准输出流,2个并行运行的线程输出都混杂在一起了。

更为重要的是,多个线程访问共享资源时,必须同步化访问以避免时间上的重叠。

我们为了防止主线程退出,整个程序终止,达不到自己想到的效果,利用了​​sleep()​​​来作为同步机制,由于这个延时,整个程序的运行时间并没有比单线程的版本更快,而且多个线程一起共享某个变量/对象,那么就有可能会丢失其中一个。
我们看一下如下代码:

from _thread import start_new_thread
import time

num = 0
def plus_one():
    global num
    for i in range(1000):
        num += 1
def minus_one():
    global num
    for i in range(1000):
        num -= 1
def main():
    start_new_thread(plus_one, ())
    start_new_thread(minus_one, ())
    time.sleep(3)
    print(num)
if __name__ == '__main__':
    main()

我们共享一个全局变量​​num​​​,启动两个线程:一个加一1000次,一个减一1000次,最后输出​​num​​的值,好像为0,但是果真如此吗?我们是一下循环100000次看看,

from _thread import start_new_thread
import time

num = 0
def plus_one():
    global num
    for i in range(100000):
        num += 1
def minus_one():
    global num
    for i in range(100000):
        num -= 1
def main():
    start_new_thread(plus_one, ())
    start_new_thread(minus_one, ())
    time.sleep(3)
    print(num)
if __name__ == '__main__':
    main()

输出​​num​​结果可能为整数,也可能为负数,也可能为0,这是因为线程执行顺序其实是随机的。

锁的概念

正因为存在上述的问题,所以引出锁的概念:想要修改一个共享对象,线程需要获得一把锁,然后进行修改,之后释放这把锁,然后才能被其他线程获取。通过​​allocate_lock()​​创建一个锁的对象,例如:

from _thread import start_new_thread, allocate_lock
import time

num = 0
mutex = allocate_lock()  # 增加一把锁
def plus_one():
    global num
    mutex.acquire()  # 获得锁

    for i in range(1000000):
        num += 1
    mutex.release()  # 释放锁
def minus_one():
    global num
    mutex.acquire()  # 获得锁
    for i in range(1000000):
        num -= 1
    mutex.release()  # 释放锁
def main():
    start_new_thread(plus_one, ())
    start_new_thread(minus_one, ())
    time.sleep(3)
    print(num)
if __name__ == '__main__':
    main()

这样执行后结果就会一直是0。

threading模块

threading是基于对象和类的较高层面上的接口,

threading.Thread((target=function_name, args=(function_parameter1, function_parameterN))

我们也首先实现一个上述加一减一的操作。

import threading

num = 0
def plus_one():
    global num

    for i in range(1000000):
        num += 1
def minus_one():
    global num
    for i in range(1000000):
        num -= 1
def main():
    t1 = threading.Thread(target=plus_one)
    t2 = threading.Thread(target=minus_one)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(num)

if __name__ == '__main__':
    main()

上锁

import threading

num = 0
mutex = threading.Lock()
def plus_one():
    global num
    mutex.acquire()
    for i in range(1000000):
        num += 1
    mutex.release()
def minus_one():
    global num
    mutex.acquire()
    for i in range(1000000):
        num -= 1
    mutex.release()
def main():
    t1 = threading.Thread(target=plus_one)
    t2 = threading.Thread(target=minus_one)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    
    print(num)
if __name__ == '__main__':
    main()

到此,我们简单的介绍了Python中两个关于线程的模块,然后通过共享变量引出锁的概念,不过到此并没有结束。比如:自定义线程、守护线程、死锁…

标签:__,thread,Python,编程,start,num,线程,多任务,def
From: https://blog.csdn.net/s44359487yad/article/details/140558908

相关文章

  • python+flask计算机毕业设计基于WEB技术的校园红歌曲库管理系统的设计与实现(程序+开题
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和互联网的广泛普及,数字化管理已成为提升工作效率与服务质量的重要手段。在校园文化建设中,红歌作为传承红色文化、......
  • 链表(Linked List)-Python实现-使用类和使用函数
    链表链表(LinkedList)单链表(SinglyLinkedList)节点类(NodeClass)链表类(LinkedListClass)使用链表类不用类的方法实现链表实现单链表使用函数实现链表具体讲解类的方法实现链表Node类LinkedList类不用类的方法实现链表创建节点添加节点删除节点搜索节点显示链表总......
  • Python-request库的详细解析
    引言在现代网络应用中,与服务器进行通信是一个非常基础且重要的功能。Python的requests库是一个非常强大且易于使用的HTTP库,它允许我们发送HTTP请求,与Web服务进行交互。本文将详细介绍requests库的使用,包括其基本概念、常用功能以及一些高级用法。安装requests库在使用req......
  • python实现爆破wifi密码
    importpywifiimporttimefrompywifiimportconst#WiFi扫描模块defwifi_scan():#初始化wifiwifi=pywifi.PyWiFi()#使用第一个无线网卡interface=wifi.interfaces()[0]#开始扫描interface.scan()foriinrange(4):t......
  • python+flask计算机毕业设计企业固定资产档案管理系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着企业规模的不断扩大和业务的日益复杂化,固定资产作为企业重要的经济资源,其管理效率直接影响到企业的运营成本和资产利用率。传统的手工......
  • python+flask计算机毕业设计汽车零件维修管理信息平台(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着汽车工业的飞速发展,汽车保有量持续增长,汽车零部件维修与管理成为汽车行业不可忽视的重要环节。传统的手工记录与管理模式已难以满足现......
  • python爬虫实现简单的代理ip池
    python爬虫实现简单的代理ip池我们在普通的爬虫过程中经常遇到一些网站对ip进行封锁的下面演示一下普通的爬虫程序使用requests.get爬取数据这段代码是爬取豆瓣排行榜的数据,使用f12来查看请求的url和数据格式代码defrequestData():#爬取数据的urlurl:s......
  • Java中的多线程编程与锁机制解析
    Java中的多线程编程与锁机制解析大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天,我们将深入探讨Java中的多线程编程与锁机制。多线程编程在现代应用开发中至关重要,它允许程序同时执行多个任务,从而提高程序的响应性和性能。我们将通过代码示例来解析Jav......
  • 基于Python星载气溶胶数据处理与反演分析
    在当前全球气候变化和环境污染问题日益突出的背景下,气溶胶研究显得尤为重要。气溶胶在大气中由直径范围在0.01微米至10微米固体和液体颗粒构成,直接或间接影响地球辐射平衡、气候变化和空气质量。尤其在“碳中和”目标的驱动下,研究气溶胶对“碳中和”的气候影响及其环境效应,不仅......
  • Java中的动态代理与AOP编程
    Java中的动态代理与AOP编程大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨Java中的动态代理和面向切面编程(AOP),这两者是构建灵活且可扩展系统的重要工具。1.动态代理概述在Java中,动态代理允许我们在运行时创建代理对象,从而可以在不修改现......