python多任务编程

1、基础知识介绍

多任务就是指同一时间内执行多个任务

两种表现形式:

并发:在一段时间内交替去执行多个任务

并行:在一段时间内一起去执行多个任务

2、进程的介绍

进程是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位。一个正在运行的程序就是一个进程

例如:正在运行的QQ,微信等他们都是进程

多进程的作用:多进程是python程序中实现多任务的一种方式,使用多进程可以大大提高程序的执行效率。

3、多进程完成多任务

3.1、步骤:

3.1.1、导入进程包

import multiprocessing

3.1.2、通过进程类创建进程对象

进程对象=multiprocessing.Process(target=任务名)

在这里插入图片描述

3.1.3、启动进程执行任务

进程对象.start()


# 导入进程模块
import multiprocessing
import time


# 编写代码
def coding():
    for i in range(3):
        print("coding...")
        time.sleep(0.2)


# 听音乐
def music():
    for i in range(3):
        print("music...")
        time.sleep(0.2)


if __name__ == '__main__':
    # coding()
    # music()
    # 通过进程类创建进程对象
    coding_process = multiprocessing.Process(target=coding)
    # 通过进程类创建进程对象
    music_process = multiprocessing.Process(target=music)
    # 启动进程
    coding_process.start()
    music_process.start()

4、进程执行带有参数的任务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-58THEi2v-1632967786095)(C:\Users\ldw\AppData\Roaming\Typora\typora-user-images\image-20210923152243361.png)]

# 导入进程模块
import multiprocessing
import time


# 编写代码
def coding(num,name):
    for i in range(num):
        print(name)
        print("coding...")
        time.sleep(0.2)


# 听音乐
def music(count):
    for i in range(count):
        print("music...")
        time.sleep(0.2)


if __name__ == '__main__':
    # coding()
    # music()
    # 通过进程类创建进程对象
    coding_process = multiprocessing.Process(target=coding,args=(3,"传智"))
    # 通过进程类创建进程对象
    music_process = multiprocessing.Process(target=music,kwargs={"count":2})
    # 启动进程
    coding_process.start()
    music_process.start()

5、获取进程编号

作用:为了方便管理,每个进程都有自己的编号,通过获取进程编号就可以快速区分不同的进程

获取当前进程编号 getpid()

获取当前进程父编号 getppid()


# 导入进程模块
import multiprocessing
import time
import os

# 编写代码
def coding(num,name):
    print("coding>>%d"%os.getpid())
    print("codingfu>>%d" % os.getppid())
    for i in range(num):
        print(name)
        print("coding...")
        time.sleep(0.2)


# 听音乐
def music(count):
    print("music>>%d" % os.getpid())
    print("musicfu>>%d" % os.getppid())
    for i in range(count):
        print("music...")
        time.sleep(0.2)


if __name__ == '__main__':
    print("主进程>>%d" % os.getpid())
    # coding()
    # music()
    # 通过进程类创建进程对象
    coding_process = multiprocessing.Process(target=coding,args=(3,"传智"))
    # 通过进程类创建进程对象
    music_process = multiprocessing.Process(target=music,kwargs={"count":2})
    # 启动进程
    coding_process.start()
    music_process.start()

6、进程间不共享全局变量

实际上创建一个子进程就是把主进程的资源进行拷贝产生一个新的进程,这里主进程和子进程是相互独立的。

import multiprocessing
my_list = []

def write_data():
    for i in range(3):
        my_list.append(i)
        print("add:",i)
    print(my_list)

def read_data():
    print("read_data",my_list)

if __name__ == '__main__':
    # 创建写入数据进程
    write_process = multiprocessing.Process(target=write_data)
    read_process = multiprocessing.Process(target=read_data)
    # 创建写入数据进程
    write_process.start()
    time.sleep(1)
    read_process.start()

7、主进程和子进程的结束顺序

​ 主进程会等待所有的子进程执行结束再结束

import multiprocessing
import time

def work():
    for i in range(10):
        print("工作中。。。。。。。")
        time.sleep(0.2)

if __name__ == '__main__':
    # 创建写入数据进程
    work_process = multiprocessing.Process(target=work)
    work_process.start()

    time.sleep(1)
    #手动结束子进程
    work_process.terminate()
    print("主进程执行完成了啦")

设置守护主进程方式:子进程对象.daemon = True

销毁子进程方式:子进程对象.terminate()

以上两种方式都能保证主进程结束后子进程销毁

8、线程的介绍

线程是程序执行的最小单位,一个进程中最少有一个线程来负责执行程序。

多个线程可共享进程所拥有的全部资源。

就想一个QQ软件(一个进程)打开两个窗口(两个线程)跟两个人聊天一样,实现多任务的同时也节省了资源。

线程的创建步骤

1、导入线程模块

import threading

2、通过线程类创建线程对象

线程对象=threading.Thread(target = 任务名)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUCjDbGC-1632967786097)(C:\Users\ldw\AppData\Roaming\Typora\typora-user-images\image-20210923161902782.png)]

3、启动线程执行任务

线程对象.start()

import threading
import time

def coding():
    for i in range(3):
        print("coding...")
        time.sleep(0.2)
def music():
    for i in range(3):
        print("music..")
        time.sleep(0.2)

if __name__=='__main__':
    coding_thread =threading.Thread(target = coding)
    music_thread = threading.Thread(target=music)
    coding_thread.start()
    music_thread.start()

9、线程执行带有参数的任务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yt5UbhmE-1632967786099)(C:\Users\ldw\AppData\Roaming\Typora\typora-user-images\image-20210923163143985.png)]

线程执行带有参数的任务传参有两种形式

1、元组方式传参:元组方式传参一定要和参数的顺序保持一致

2、字典方式传参:字典方式传参字典中的key一定要和参数名保存一致

import threading
import time

def coding(num):
    for i in range(num):
        print("coding...")
        time.sleep(0.2)
def music(count):
    for i in range(count):
        print("music..")
        time.sleep(0.2)

if __name__=='__main__':
    coding_thread =threading.Thread(target = coding,args=(3,))
    music_thread = threading.Thread(target=music,kwargs={"count":1})
    coding_thread.start()
    music_thread.start()

10、主线程和子线程的结束顺序

主线程会等待所有子线程执行结束后再结束

import threading

def work():
    for i in range(10):
        print("work...")
        time.sleep(0.2)
if __name__ =='__main__':
    #方法1 参数方式
    #work_thread = threading.Thread(target=work,daemon=True)
    work_thread = threading.Thread(target=work)
    # 方式2
    work_thread.daemon=True
    work_thread.start()
    time.sleep(1)

设置守护主线程的目的是主线程退出子线程销毁,不让主线程再等待子线程去执行

设置守护主线程的两种方式:

1、threading.Thread(target=work,daemon=True)

2、线程对象.setDaemon(True)

11、线程的执行顺序

获取当前的线程信息

import threading

def get_info():
    current_thread = threading.current_thread()
    print(current_thread)

if __name__ =='__main__':
    for i in range(10):
        sub_thread =threading.Thread(target=get_info)
        sub_thread.start()

线程之间执行是无序的,是由CPU调度决定某个线程先执行的

12、线程间共享全局变量

my_list =[]
def write_data():
    for i in range(3):
        print("add",i)
        my_list.append(i)
    print("write",my_list)

def read_data():
    print("read",my_list)

if __name__ == '__main__':
    write_thread = threading.Thread(target=write_data)
    read_thread = threading.Thread(target=read_data)
    
    write_thread.start()
    time.sleep(1)
    read_thread.start()

13、线程间共享全局变量

import  threading       
g_num =0
def sum_num1():
    for i in range(100000):
        global g_num
        g_num +=1
    print("g_num",g_num)
    
def sum_num2():
    for i in range(100000):
        global g_num
        g_num+=1
    print("g_num2",g_num)

if __name__ == '__main__':
    sum1_thread = threading.Thread(target=sum_num1)
    sum2_thread = threading.Thread(target=sum_num2)
    
    sum1_thread.start()
    sum2_thread.start()

线程之间共享全局变量数据出现错误

解决办法:互斥锁

14、互斥锁

对共享数据进行锁定,保证同一时刻只有一个线程去操作

步骤

1、创建 mutex = threading.lock()

2、上锁 mutex.acquire()

3、释放锁 mutex.release()

import threading

g_num = 0


def sum_num1():
    mutex.acquire()
    for i in range(100000):
        global g_num
        g_num += 1
    mutex.release()
    print("g_num", g_num)


def sum_num2():
    mutex.acquire()
    for i in range(100000):
        global g_num
        g_num += 1
    mutex.release()
    print("g_num2", g_num)


if __name__ == '__main__':
    mutex = threading.Lock()
    sum1_thread = threading.Thread(target=sum_num1)
    sum2_thread = threading.Thread(target=sum_num2)

    sum1_thread.start()
    sum2_thread.start()

15、死锁

一直等待对方释放锁的情景就是死锁

死锁的结果:会造成应用程序的停止响应,不能再处理其它任务了

16、进程和线程的区别

16.1、关系对比

线程是依附在进程里面的,没有进程就没有线程

一个进程默认提供一条线程,进程可以创建多个线程

16.2、区别对比

进程之间不共享全局变量

线程之间共享全局变量,但是要注意资源竞争,解决办法:互斥锁或者线程同步

创建进程的资源开销大于线程的资源开销

进程是惭怍系统分配的基本单位,线程是CPU调度的基本单位

线程是不能够独立执行,必须依存在进程中

16.3、优缺点对比

进程

优点:可以用多核

缺点:资源开销大

线程

优点:资源开销小

缺点:不能用多核

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值