Python多任务教程

一.并发和并行

  1. 多任务:一定时间段内,充分利用cpu资源,同时去执行多个任务

  2. 并发: 快速交替的 去执行多任务

  3. 并行: 真正同时的 去执行多任务 ,就是同时进行

二.多进程

1.多进程入门

知识点:

  1. 进程含义: 运行中的程序

  2. 进程特点: cpu资源分配的 最小单位

  3. 多进程模块: multiprocessing

  4. 进程类: Process

使用步骤:

  1. 导包 : import multiprocessing

  2. 创建对象 : 子进程对象 = multiprocessing.Process(target=任务名)

  3. 开启进程 : 子进程对象.start()

示例:

import multiprocessing
import time
# 任务1
def dance():
    for i in range(5):
        time.sleep(0.1)
        print('跳舞',i)
# 任务2
def sing():
    for i in range(5):
        time.sleep(0.3)
        print('唱歌',i)
# 多进程放到main内
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=dance)
    p2 = multiprocessing.Process(target=sing)
    # 2.开启进程
    p1.start()
    p2.start()

2.os模块获取进程编号

知识点:

获取当前进程id: os.getpid()   pid: processing id

获取父进程id: os.getppid()   ppid: parent processing id

示例:

import multiprocessing
import os
import time
# 任务1
def dance():
    print('dance子进程:', os.getpid(), os.getppid())
    for i in range(5):
        time.sleep(0.1)
        print('跳舞',i)
# 任务2
def sing():
    print('sing子进程:', os.getpid(),os.getppid())
    for i in range(5):
        time.sleep(0.3)
        print('唱歌',i)
# 多进程放到main内
if __name__ == '__main__':
    print('main主进程:',os.getpid())
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=dance)
    p2 = multiprocessing.Process(target=sing)
    # 2.开启进程
    p1.start()
    p2.start()

3.Process()类的传参,2种方式

知识点:

  • args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致

  • kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致

示例:

import multiprocessing
import os
import time
# 任务1
def dance(num):
    print('dance子进程:', os.getpid(), os.getppid())
    for i in range(num):
        time.sleep(0.1)
        print('跳舞',i)
# 任务2
def sing(num):
    print('sing子进程:', os.getpid(), os.getppid())
    for i in range(num):
        time.sleep(0.3)
        print('唱歌',i)
# 多进程放到main内
if __name__ == '__main__':
    print('main主进程:', os.getpid())
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=dance,args=(5,))
    p2 = multiprocessing.Process(target=sing,kwargs={'num':5})
    # 2.开启进程
    p1.start()
    p2.start()

4.获取当前进程信息

知识点:

  1. 获取当前进程对象: multiprocessing.current_process()

  2. 获取当前进程name: multiprocessing.current_process().name

  3. 获取当前进程pid: multiprocessing.current_process().pid

示例:

import multiprocessing
# 任务1
def dance():
    print('dance子进程对象:', multiprocessing.current_process())
    print('dance子进程name:', multiprocessing.current_process().name)
    print('dance子进程id:', multiprocessing.current_process().pid)

# 任务2
def sing():
    print('sing子进程对象:', multiprocessing.current_process())
    print('sing子进程name:', multiprocessing.current_process().name)
    print('sing子进程id:', multiprocessing.current_process().pid)

# 多进程放到main内
if __name__ == '__main__':
    print('main主进程对象:', multiprocessing.current_process())
    print('main主进程name:', multiprocessing.current_process().name)
    print('main主进程id:', multiprocessing.current_process().pid)
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=dance,name='danceProcess')
    p2 = multiprocessing.Process(target=sing,name='singProcess')
    # 2.开启进程
    p1.start()
    p2.start()

5.注意事项

1. 多进程间不能共享全局变量:

import multiprocessing

mylist = []
# 写
def write():
    global mylist
    mylist = [1,2,3,4,5]
    print('write:',mylist) # [1, 2, 3, 4, 5]
# 读
def read():
    global mylist
    print('read:',mylist)  # []  说明多个进程间不共享全局变量

# 多进程需要放到main内
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=write)
    p2 = multiprocessing.Process(target=read)
    # 2.开启进程
    p1.start()
    p2.start()

2. 主进程默认等待子进程结束再结束:

import multiprocessing
import time


# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=task)
    # 2.开启进程
    p1.start()

    # 3.主进程等待0.5秒
    time.sleep(0.5)
    print('主进程中最后一行代码....')

2. 主进程默认等待子进程结束再结束:

import multiprocessing
import time


# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=task)
    # 2.开启进程
    p1.start()

    # 3.主进程等待0.5秒
    time.sleep(0.5)
    print('主进程中最后一行代码....')

3. 多进程执行是无序的:

import multiprocessing
import time

# 任务
def show():
    time.sleep(2)
    print(multiprocessing.current_process().name)
# 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
# 多任务
if __name__ == '__main__':
    for _ in range(5):
        # 创建进程对象
        p = multiprocessing.Process(target=show)
        # 开启进程
        p.start()

6.设置子进程跟着主进程一起结束#

知识点:

方式1 设置子进程守护主进程:  子进程对象.daemon = True   注意: 需要在开启进程之前设置   

       :                          daemon/ˈdiːmən/守护进程


方式2 手动销毁子进程     :  子进程对象.terminate()    terminate:结束,终止

1. 守护主进程:

import multiprocessing
import time


# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=task)
    # 方式1: 开启子进程之前设置守护主进程
    p1.daemon = True
    # 2.开启进程
    p1.start()


    # 3.主进程等待0.5秒
    time.sleep(0.5)
    print('主进程中最后一行代码....')

2. 手动销毁子进程:

import multiprocessing
import time


# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建进程对象
    p1 = multiprocessing.Process(target=task)

    # 2.开启进程
    p1.start()

    # 3.主进程等待0.5秒
    time.sleep(0.5)
    print('主进程中最后一行代码....')
    
    # 方式2: 手动销毁子进程
    p1.terminate()

三.多线程

1.多线程入门

知识点:

  1. 线程含义: 进程中 执行代码的 一个分支 (一个进程至少有一个线程)

  2. 线程作用: 线程是 cpu调度的 最小单位

  3. 多线程模块: threading

  4. 线程类: Thread

使用步骤:

  1. 导包 : import threading
  2. 创建对象 : 子线程对象 = threading.Thread(target=任务名)
  3. 开启进程 : 子线程对象.start()

示例:

import threading


# 任务1
def dance():
    for i in range(5):
        print('跳舞',i)
# 任务2
def sing():
    for i in range(5):
        print('唱歌',i)

# 多任务
if __name__ == '__main__':
    # 1.创建子线程对象
    t1 = threading.Thread(target=dance)
    t2 = threading.Thread(target=sing)
    # 2.开启线程
    t1.start()
    t2.start()

2.多线程的传参

知识点:

args: 以元组方式传参 注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致

kwargs: 以字典方式传参 注意:需要{k:v}形式传参,k必须和任务的形参名一致

与多进程一模一样

示例:

import threading
"""
args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
"""
# 任务1
def dance(num):
    for i in range(num):
        print('跳舞', i)

# 任务2
def sing(num):
    for i in range(num):
        print('唱歌', i)

# 多任务
if __name__ == '__main__':
    # 1.创建子线程对象
    t1 = threading.Thread(target=dance,args=(5,))
    t2 = threading.Thread(target=sing,kwargs={'num':5})
    # 2.开启线程
    t1.start()
    t2.start()

3.多线程注意事项

  1. 多线程是在一个进程中
import os
import threading
"""
args: 以元组方式传参   注意:如果只有一个参数需要加逗号, 如果多个参数顺序要任务参数顺序一致
kwargs: 以字典方式传参  注意:需要{k:v}形式传参,k必须和任务的形参名一致
"""
# 任务1
def dance(num):
    print(f'dance子线程中当前进程pid:{os.getpid()}')
    for i in range(num):
        print('跳舞', i)

# 任务2
def sing(num):
    print(f'sing子线程中当前进程pid:{os.getpid()}')
    for i in range(num):
        print('唱歌', i)

# 多任务
if __name__ == '__main__':
    print(f'main主线程中当前进程pid:{os.getpid()}')
    # 1.创建子线程对象
    t1 = threading.Thread(target=dance,args=(5,))
    t2 = threading.Thread(target=sing,kwargs={'num':5})
    # 2.开启线程
    t1.start()
    t2.start()

2. 多线程是可以共享全局变量

import threading

mylist = []
# 写
def write():
    global mylist
    mylist = [1,2,3,4,5]
    print('write:',mylist) # [1, 2, 3, 4, 5]
# 读
def read():
    global mylist
    print('read:',mylist)  # [1, 2, 3, 4, 5] 访问到了write线程修改后的内容说明多线程共享全局变量

if __name__ == '__main__':
    # 1.创建线程对象
    t1 = threading.Thread(target=write)
    t2 = threading.Thread(target=read)
    # 2.开启线程
    t1.start()
    t2.start()

3. 主线程默认等待子线程结束再结束

import threading
import time

# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建线程对象
    t = threading.Thread(target=task)
    # 2.开启线程
    t.start()

    # 3.为了效果明显点,主线程等待0.5秒
    time.sleep(0.5)
    print('主线程中最后一行代码....')

4. 多线程是无序的

import threading
import time

# 任务
def show():
    time.sleep(1)
    print(threading.current_thread().name)

# 多任务
if __name__ == '__main__':
    for _ in range(5):
        # 创建线程对象
        p = threading.Thread(target=show)
        # 开启线程
        p.start()

4.设置守护主线程

知识点:

方式1: daemon属性        t.daemon = True       daemon/ˈdiːmən/守护进程
    
方式2: setDaemon()方法   t.setDaemon(True)

一个是属性,一个是方法,用哪个都可以

示例:

import threading
import time

# 任务
def task():
    for i in range(10):
        print('任务进行中...')
        time.sleep(0.2)

# 多任务
if __name__ == '__main__':
    # 1.创建线程对象
    t = threading.Thread(target=task)
    
    # 方式1: daemon属性
    # t.daemon = True

    # 方式2: setDaemon()方法
    t.setDaemon(True)
    # 2.开启线程
    t.start()

    # 3.为了效果明显点,主线程等待0.5秒
    time.sleep(0.5)
    print('主线程中最后一行代码....')

5.获取当前线程信息

知识点:

  1. 获取当前线程对象:threading.current_thread()

  2. 获取当前线程name:threading.current_thread().name

  3. 获取当前线程id:threading.current_thread().native_id

示例:

import threading

def dance():
    print(f'dance当前线程对象:{threading.current_thread()}')
    print(f'dance当前线程name:{threading.current_thread().name}')
    print(f'dance当前线程id:{threading.current_thread().native_id}')

def sing():
    print(f'sing当前线程对象:{threading.current_thread()}')
    print(f'sing当前线程name:{threading.current_thread().name}')
    print(f'sing当前线程id:{threading.current_thread().native_id}')


if __name__ == '__main__':
    print(f'main当前线程对象:{threading.current_thread()}')
    print(f'main当前线程name:{threading.current_thread().name}')
    print(f'main当前线程id:{threading.current_thread().native_id}')

    # 1.创建线程对象
    t1 = threading.Thread(target=dance,name='DanceThread')
    t2 = threading.Thread(target=sing,name='SingThread')
    # 2.开启线程
    t1.start()
    t2.start()

6.线程安全问题

1. 出现的线程安全问题:

import threading

sum = 0

def sum1():
    global sum
    for i in range(1000000):
        sum += 1
    print(sum) # 1114834

def sum2():
    global sum
    for i in range(1000000):
        sum += 1
    print(sum)  # 1339347

# 单任务不会出现问题 正常结果  1000000 2000000
# 多任务出现了问题
if __name__ == '__main__':
    # 1.创建线程对象
    t1 = threading.Thread(target=sum1)
    t2 = threading.Thread(target=sum2)
    # 2.开启线程
    t1.start()
    t2.start()

2. 锁机制解决线程安全问题:

import threading

sum = 0

def sum1(lock):
    lock.acquire() # 加锁
    global sum
    for i in range(1000000):
        sum += 1
    print(sum) # 1000000
    lock.release() # 释放锁

def sum2(lock):
    lock.acquire()  # 加锁
    global sum
    for i in range(1000000):
        sum += 1
    print(sum)  # 2000000
    lock.release()  # 释放锁

# 单任务不会出现问题 正常结果  1000000 2000000
# 多任务出现了问题 ,利用锁机制解决问题
if __name__ == '__main__':
    # 创建一个锁,保证两个任务用的是同一个锁
    lock= threading.Lock()
    # 1.创建线程对象
    t1 = threading.Thread(target=sum1,args=(lock,))
    t2 = threading.Thread(target=sum2,args=(lock,))
    # 2.开启线程
    t1.start()
    t2.start()

3. join解决线程安全问题:

import threading

sum = 0


def sum1():
    global sum
    for i in range(1000000):
        sum += 1
    print(sum)  # 1000000

def sum2():
    global sum
    for i in range(1000000):
        sum += 1
    print(sum)  # 2000000
# 学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
# 单任务不会出现问题 正常结果  1000000 2000000
# 多任务出现了问题 ,利用join解决问题
if __name__ == '__main__':
    # 1.创建线程对象
    t1 = threading.Thread(target=sum1)
    t2 = threading.Thread(target=sum2)
    # 2.开启线程
    t1.start()
    t1.join()  # t1线程告诉其他线程等我执行完,你们其他线程再执行

    t2.start()

四.进程和线程对比

关系

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

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

区别

  1. 进程之间不共享全局变量
  2. 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法是互斥锁或者线程同步
  3. 创建进程的资源开销要比创建线程的资源开销要大
  4. 进程是操作系统 资源分配 的基本单位,线程是 CPU调度 的基本单位
  5. 线程不能够独立执行,必须依存在进程中
  6. 多进程开发比单进程多线程开发稳定性要强

优缺点

进程优缺点:
优点:可以用多核
缺点:资源开销大

线程优缺点:
优点:资源开销小
缺点:不能使用多核

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python多任务教程 - Python技术站

(0)
上一篇 2023年3月31日
下一篇 2023年3月31日

相关文章

  • python3实现字符串的全排列的方法(无重复字符)两种解决方法

    抛出问题 求任意一个字符串的全排列组合,例如a=’123′,输出 123,132,213,231,312,321。(暂时假定字符串没有重复) 解决方案 目前有两种解决的方法 方法一: def str_sort(s=”): if len(s) <= 1: return [s] str_list = [] for i in range(len(s)): …

    Python开发 2023年3月31日
    00
  • Python类和对象的绑定方法及非绑定方法

    类中定义的方法大致可以分为两类:绑定方法和非绑定方法。其中绑定方法又可以分为绑定到对象的方法和绑定到类的方法。 一、绑定方法 1 对象的绑定方法 在类中没有被任何装饰器修饰的方法就是 绑定到对象的方法,这类方法专门为对象定制。 class Person: country = “China” def __init__(self, name, age): sel…

    Python开发 2023年3月31日
    00
  • Python关于异常处理的教程

    一、什么是异常 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下 1 语法错误 语法错误,根本过不了python解释器的语法检测,必须在程序执行前就改正。 # 语法错误示范一 if # 语法错误示范二 def test: pass # 语法错误…

    Python开发 2023年3月31日
    00
  • python3教程:*和**的打包和解包的用法

    一. 打包参数 1. * 的作用:在函数定义中,收集所有的位置参数到一个新的元组,并将这个元组赋值给变量args >>> def f(*args): print(args) >>> f() () >>> f(1) (1,) >>> f(1, 2, 3, 4) (1, 2, 3, 4) &…

    Python开发 2023年4月2日
    00
  • Python模块:subprocess模块教程

    一.subprocess模块 subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法,如: os.system os.spawn* 1.subprocess模块中的常用函数 函数 描述 subprocess…

    Python开发 2023年4月2日
    00
  • python中如何修改文件?

    修改的概念:对于硬盘上数据的修改, 根本没有改的操作, 只有覆盖操作 修改的流程:文件的修改都是数据加载到内存中, 在内存中修改完再覆盖入硬盘 一.修改方式一 1.修改过程 先以 r 模式打开源文件,将源文件内容全部读入内存 然后在内存中完成修改 再以 w 模式打开源文件,将修改后的内容覆盖入源文件 2.优缺点 优点 : 不须要硬盘预留足够的空间 缺点 : …

    python 2023年4月17日
    00
  • Python递归的几个经典案例

    当我们碰到诸如需要求阶乘或斐波那契数列的问题时,使用普通的循环往往比较麻烦,但如果我们使用递归时,会简单许多,起到事半功倍的效果。这篇文章主要和大家分享一些和递归有关的经典案例,结合一些资料谈一下个人的理解,也借此加深自己对递归的理解和掌握一些递归基础的用法。 一、递归的简介 1、递归的百度百科定义 程序调用自身的编程技巧称为递归( recursion)。 …

    Python开发 2023年4月2日
    00
  • Python教程:selenium模块用法教程

    1.介绍 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器 from selenium import webdriver browser=webd…

    Python开发 2023年3月31日
    00
合作推广
合作推广
分享本页
返回顶部