前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 多线程多进程

Python 多线程多进程

作者头像
小菠萝测试笔记
发布2021-03-27 17:23:58
6400
发布2021-03-27 17:23:58
举报

前提

  • 我是参考 Github Python 100 天的文章写的,再结合自己的小练习,总结
  • 最近在面大厂,发现许多大厂都会问 Python 的多线程、多进程,所以我觉得很有必要总结学习下

什么是进程

操作系统中执行的一个程序,类似微信、QQ,每个程序都是一个进程

在这里插入图片描述
在这里插入图片描述

概念

  • 它是 CPU 最小资源分配单元
  • 操作系统会给进程分配内存空间,每个进程都会有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据
  • 操作系统管理所有进程的执行,为它们合理的分配资源

fork、spawn

  • 进程可以通过 fork、spawn 的方式来创建新的进程来执行其他任务
  • 不过新的进程有自己独立的内存空间、数据栈
  • 因此不同进程间需要通过通信机制(IPC)来实现数据共享
常见通信机制
  • 管道
  • 信号
  • 套接字
  • 共享内存区

什么是线程

  • 进程中可以拥有多个并发的执行线索
  • 它是 CPU 最小调度的执行单元

特点

  • 同一个进程下的线程共享相同的上下文
  • 相对于进程来说,线程间的信息共享和通信更加容易

单核 CPU 系统注意事项

  • 真正的并发是不可能的
  • 因为在某个时刻,CPU 只能运行唯一的一个线程
  • 多个线程共享了 CPU 的执行时间

多线程的好处

  • 提升程序的性能和改善用户体验
  • 今天日常使用的软件几乎都用到了多线程

多线程的坏处

  • 站在其他进程的角度,多线程的程序对其他程序并不友好,因为它占用了更多的 CPU 执行时间,导致其他程序无法获得足够的 CPU 执行时间
  • 编写和调试多线程的程序对开发者要求较高

Python 实现并发编程的方式

  • 多进程
  • 多线程
  • 多进程+多线程

Python 中的多进程

Linux 下的 fork 函数
  • Linux 操作系统上提供了 系统调用来创建进程

fork()

  • 调用 函数的是父进程

fork()

  • 创建的是子进程
  • 子进程是父进程的拷贝
  • 但子进程有自己的 PID
  • 函数非常特殊,它会返回两次,父进程中调用 fork() 会返回子进程的 PID,子进程中调用 fork() 得到的都是0

fork()

Python 提供的 fork 函数

os 模块提供了 fork()

Window 下没有fork()的调用
  • 实现跨平台的多进程变成,可以使用 multiprocessing 模块的 Process 类来创建子进程
  • 还提供了更高级的封装,例如批量启动进程的进程池 pool、用于进程间同喜你的队列 Queue 和管道 Pipe

使用多进程和不使用多进程的区别(写代码)

不使用多进程

代码语言:javascript
复制
from random import randint
from time import time, sleep

def download_task(filename):
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
    start = time()
    download_task('Python从入门到住院.pdf')
    download_task('Peking Hot.avi')
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))

if __name__ == '__main__':
    main()
执行结果
代码语言:javascript
复制
开始下载Python从入门到住院.pdf...
Python从入门到住院.pdf下载完成! 耗费了10秒
开始下载Peking Hot.avi...
Peking Hot.avi下载完成! 耗费了9秒
总共耗费了19.02秒.

可以看到需要先等第一个文件下载完才能下载第二个文件,效率很低

使用多进程

代码语言:javascript
复制
from random import randint
from time import time, sleep
from multiprocessing import Process

def download_task(filename):
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def main2():
    start = time()
    p1 = Process(target=download_task,args=("Python从入门到住院.pdf",))
    p1.start()
    p2 = Process(target=download_task, args=("Peking Hot.avi",))
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
    main2()
执行结果
代码语言:javascript
复制
开始下载Python从入门到住院.pdf...
开始下载Peking Hot.avi...
Python从入门到住院.pdf下载完成! 耗费了6秒
Peking Hot.avi下载完成! 耗费了10秒
总共耗费了10.17秒.

两个任务同时执行,总耗时不再是两个任务的时间总和

知识点
  • Process:通过 Process 类创建进程对象
  • target:通过 target 参数传入一个函数名来表示进程启动后要执行的代码
  • args:是一个元组,代表传递给函数的参数列表
  • start:Process 的 start() 方法来启动进程
  • join:Process 的 join() 方法表示等待进程执行结束,才会往下执行

Python 中的多线程

前言

推荐 threading 模块来实现多线程编程,它提供了更好的面向对象封装

多线程的实现方式

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
__title__  = 
__Time__   = 2021/3/19 18:17
__Author__ = 小菠萝测试笔记
__Blog__   = https://www.cnblogs.com/poloyy/
"""

from random import randint
from threading import Thread
from time import time, sleep

def download_task(filename):
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main3():
    start = time()
    p1 = Thread(target=download_task,args=("Python从入门到住院.pdf",))
    p1.start()
    p2 = Process(target=download_task, args=("Peking Hot.avi",))
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
    main3()
执行结果
代码语言:javascript
复制
开始下载Python从入门到住院.pdf...
开始下载Peking Hot.avi...
Peking Hot.avi下载完成! 耗费了6秒
Python从入门到住院.pdf下载完成! 耗费了8秒
总共耗费了8.01秒.

一样执行效率高很多

自定义线程类

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
__title__  = 
__Time__   = 2021/3/19 18:17
__Author__ = 小菠萝测试笔记
__Blog__   = https://www.cnblogs.com/poloyy/
"""

from random import randint
from threading import Thread
from time import time, sleep

class downLoadTask(Thread):
    def __init__(self,filename):
        super().__init__()
        self.filename = filename

    def run(self) -> None:
        print('开始下载%s...' % self.filename)
        time_to_download = randint(5, 10)
        sleep(time_to_download)
        print('%s下载完成! 耗费了%d秒' % (self.filename, time_to_download))

def main3():
    start = time()
    p1 = downLoadTask("Python从入门到住院.pdf")
    p2 = downLoadTask("Peking Hot.avi")
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))

if __name__ == '__main__':
    main3()
执行结果
代码语言:javascript
复制
开始下载Python从入门到住院.pdf...
开始下载Peking Hot.avi...
Peking Hot.avi下载完成! 耗费了6秒
Python从入门到住院.pdf下载完成! 耗费了9秒
总共耗费了9.00秒.

也是一样的高效运行

重点知识:start 和 run 方法的区别

比较点

start

run

作用

启动线程,获取 CPU 时间片

运行线程指定的代码块

线程状态

可运行状态

运行状态

调用次数

一个线程只能调用一次

可以重复调用

运行线程

创建了一个子线程,线程名是自己命名的

在主线程中调用了一个普通函数

注意点

想用多线程,必须调用 start()

Python 中的协程

什么是协程

Python 中,单线程+异步 I/O 的编程模型

协程的优势
  • 极高的执行效率
  • 子程序切换不是线程切换,而是由程序本身控制,没有线程切换的开销
  • 不需要多线程的所机制,只有一个线程,所以不存在同时写变量冲突,在协程中控制共享资源不用加锁,只需要判断状态就好了,所以执行效率比多线程高很多
重点

要充分利用 CPU 的多核特性,应该使用多进程+协程的方式

待更新

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前提
  • 什么是进程
    • 概念
      • fork、spawn
        • 常见通信机制
    • 什么是线程
      • 特点
        • 单核 CPU 系统注意事项
          • 多线程的好处
            • 多线程的坏处
              • Python 实现并发编程的方式
                • Linux 下的 fork 函数
                • Python 提供的 fork 函数
                • Window 下没有fork()的调用
            • Python 中的多进程
            • 使用多进程和不使用多进程的区别(写代码)
              • 不使用多进程
                • 执行结果
              • 使用多进程
                • 执行结果
                • 知识点
                • 前言
            • Python 中的多线程
              • 多线程的实现方式
                • 执行结果
              • 自定义线程类
                • 执行结果
              • 重点知识:start 和 run 方法的区别
                • 什么是协程
                • 协程的优势
                • 重点
            • Python 中的协程
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档