1.什么是并发编程

并发编程是实现多任务协同处理,改善系统性能的方式。Python中实现并发编程主要依靠

进程(Process):进程是计算机中的程序关于某数据集合的一次运行实例,是操作系统进行资源分配的最小单位

线程(Thread):线程被包含在进程之中,是操作系统进行程序调度执行的最小单位

协程(Coroutine):协程是用户态执行的轻量级编程模型,由单一线程内部发出控制信号进行调度

直接上一张图看看三者概念间的关系。

这张图说明了什么?首先,一条线程是进程中一个单一的顺序控制流,一个进程可以并发多个线程执行不同任务。协程由单一线程内部发出控制信号进行调度,而非受到操作系统管理,因此协程没有切换开销和同步锁机制,具有极高的执行效率。

进程、线程、协程间的特性决定了它们的应用场景不同:

协程常用于IO密集型工作,例如网络资源请求等;而进程、线程常用于计算密集型工作,例如科学计算、人工神经网络等。

接下来对每种并发编程方法进行详细阐述。

2.进程与多进程

Python多进程依赖于标准库mutiprocessing,进程类Process的常用方法如下

序号 方法 含义
1 start() 创建一个Process子进程实例并执行该实例的run()方法
2 run() 子进程需要执行的目标任务
3 join() 主进程阻塞等待子进程直到子进程结束才继续执行,可以设置等待超时时间timeout
4 terminate() 终止子进程
5 is_alive() 判断子进程是否终止
6 daemon 设置子进程是否随主进程退出而退出

创建多进程任务的实例如下

import os, time
import multiprocessing

class myProcess(multiprocessing.Process):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.name = kwargs['name']

    def run(self):
        print("process name:", self.name)
        for i in range(10):
            print(multiprocessing.current_process(), "process pid:",
                  os.getpid(), "正在执行...")
            time.sleep(0.2)

if __name__ == "__main__":
    task = myProcess(name="testProcess")
    task.start()
    task.join()		# 该语句会阻塞主进程直至子进程结束
    print("----------------")

注意:Windows系统在子进程结束后会立即自动清除子进程实例;而Linux系统子进程实例仅当主进程结束后才被回收,在子进程结束但主进程仍在运行的时间内处于僵尸进程状态,会造成性能损失甚至死锁。对子进程实例的手动回收可以通过

p.terminate()
p.join()

完成,此外,start()函数也有清除僵尸进程的功能。在使用多进程处理任务时并非进程越多越好,因为进程切换会造成性能开销。

3.线程与多线程

Python多线程依赖于标准库threading,线程类Thread的常用方法如下表:

序号 方法 含义
1 start() 创建一个Thread子线程实例并执行该实例的run()方法
2 run() 子线程需要执行的目标任务
3 join() 主进程阻塞等待子线程直到子线程结束才继续执行,可以设置等待超时时间timeout
4 is_alive() 判断子线程是否终止
5 daemon 设置子线程是否随主进程退出而退出

关于线程与进程的关系,还有一个很生动的例子

把一条公路看作一道进程,那么公路上的各个车道就是进程中的各个线程。这些线程(车道)共享了进程(道路)的公共资源;这些线程(车道)之间可以并发执行(各个车道相对独立),也可以互相同步(交通信号灯)。

rsrc = 10
lock = threading.Lock()

def task1(name):
    global rsrc, lock
    for i in range(5):
        with lock:
            rsrc  = 1
            print("task1:", rsrc)
    return name   "has been done!"

def task2(name):
    global rsrc, lock
    for i in range(5):
        lock.acquire()
        rsrc -= 1
        print("task2:", rsrc)
        lock.release() 
    return name   "has been done!"

结果如下

在多线程并发过程中,若没有控制好线程间的执行逻辑,将可能产生死锁现象,可以使用with关键词在线程访问临界区结束后自动释放锁,也可使用release()方法手动释放句柄。

4.协程与多协程

协程适用于I/O密集型而非计算密集型场景。在协程发起I/O请求后返回结果前往往有大量闲置时间——该时间可能用于网络数据传输、获取协议头、服务器查询数据库等,而I/O请求本身并不耗时,因此协程可以发送一个请求后让渡给系统干别的事,这就是协程提高性能的原因。

协程编程的框架如下:

  • 创建协程对象并将其封装成任务实例;
  • 创建事件循环实例并监听任务队列;
  • 获取协程结果(可在事件循环结束后获取,或提前添加回调函数)。

一个嵌套协程的示例如下:

import asyncio, time

# 内层协程
async def do_some_work(x):
    print('Waiting: ', x)
    await asyncio.sleep(x)
return 'Done after {}s'.format(x)

def OnCallBack(res):
print(res.result())

# 外层协程main
async def main():
    # 创建三个协程对象并封装成任务
    task1 = asyncio.ensure_future(do_some_work(1))
    task2 = asyncio.ensure_future(do_some_work(8))
    task3 = asyncio.ensure_future(do_some_work(4))
    # 添加回调
    task1.add_done_callback(OnCallBack)
    task2.add_done_callback(OnCallBack)
    task3.add_done_callback(OnCallBack)
    # 内层任务列表
    tasks = [task1, task2, task3]
	# 将列表转为可等待对象
    dones, pendings = await asyncio.wait(tasks)

# 外层协程func
async def func():
    for i in range(5):
        print("func:", i)

# 外层任务列表
tasks = [asyncio.ensure_future(func()), asyncio.ensure_future(main())]
# 创建事件循环
loop = asyncio.get_event_loop()
start = time.time()
# 监听异步任务
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("总耗时:", end - start)

5.总结

看了这么多概念可能有点晕了,下面这张表总结了本文的内容。总得来说,进程、线程、协程各有各的应用场景,不能说多进程、多线程、多协程就一定好,而是要根据具体的使用情况来确定。

到此这篇关于一文搞懂Python中的进程,线程和协程的文章就介绍到这了,更多相关Python进程 线程 协程内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

一文搞懂Python中的进程,线程和协程的更多相关文章

  1. iOS:核心图像和多线程应用程序

    我试图以最有效的方式运行一些核心图像过滤器.试图避免内存警告和崩溃,这是我在渲染大图像时得到的.我正在看Apple的核心图像编程指南.关于多线程,它说:“每个线程必须创建自己的CIFilter对象.否则,你的应用程序可能会出现意外行为.”这是什么意思?我实际上是试图在后台线程上运行我的过滤器,所以我可以在主线程上运行HUD(见下文).这在coreImage的上下文中是否有意义?

  2. ios – 多个NSPersistentStoreCoordinator实例可以连接到同一个底层SQLite持久性存储吗?

    我读过的关于在多个线程上使用CoreData的所有内容都讨论了使用共享单个NSPersistentStoreCoordinator的多个NSManagedobjectContext实例.这是理解的,我已经使它在一个应用程序中工作,该应用程序在主线程上使用CoreData来支持UI,并且具有可能需要一段时间才能运行的后台获取操作.问题是NSPersistentStoreCoordinator会对基础

  3. ios – XCode断点应该只挂起当前线程

    我需要调试多线程错误.因此,为了获得生成崩溃的条件,我需要在代码中的特定点停止一个线程,并等待另一个线程到达第二个断点.我现在遇到的问题是,如果一个线程遇到断点,则所有其他线程都被挂起.有没有办法只停止一个线程,让其他线程运行,直到它们到达第二个断点?)其他更有趣的选择:当你点击第一个断点时,你可以进入控制台并写入这应该在该断点处暂停当前上下文中的线程一小时.然后在Xcode中恢复执行.

  4. ios – 在后台线程中写入Realm后,主线程看不到更新的数据

    >清除数据库.>进行API调用以获取新数据.>将从API检索到的数据写入后台线程中的数据库中.>从主线程上的数据库中读取数据并渲染UI.在步骤4中,数据应该是最新数据,但我们没有看到任何数据.解决方法具有runloops的线程上的Realm实例,例如主线程,updatetothelatestversionofthedataintheRealmfile,因为通知被发布到其线程的runloop.在后台

  5. ios – NSURLConnectionLoader线程中的奇怪崩溃

    我们开始看到我们的应用启动时发生的崩溃.我无法重现它,它只发生在少数用户身上.例外情况是:异常类型:EXC_BAD_ACCESS代码:KERN_INVALID_ADDRESS位于0x3250974659崩溃发生在名为com.apple.NSURLConnectionLoader的线程中在调用时–[NSBlockOperationmain]这是该线程的堆栈跟踪:非常感谢任何帮助,以了解可能导致这种崩

  6. ios – 合并子上下文时的NSObjectInaccessbileExceptions

    我尝试手动重现,但失败了.是否有其他可能发生这种情况的情况,是否有处理此类问题的提示?解决方法在创建子上下文时,您可以尝试使用以下行:

  7. ios – 从后台线程调用UIKit时发出警告

    你如何处理项目中的这个问题?

  8. ios – 在SpriteKit中,touchesBegan在与SKScene更新方法相同的线程中运行吗?

    在这里的Apple文档AdvancedSceneProcessing中,它描述了更新方法以及场景的呈现方式,但没有提到何时处理输入.目前尚不清楚它是否与渲染循环位于同一个线程中,或者它是否与它并发.如果我有一个对象,我从SKScene更新方法和touchesBegan方法(在这种情况下是SKSpriteNode)更新,我是否要担心同步对我的对象的两次访问?解决方法所以几天后没有回答我设置了一些实验

  9. ios – 在后台获取中加载UIWebView

    )那么,有一种方法可以在后台加载UIWebView吗?解决方法如果要从用户界面更新元素,则必须在应用程序的主队列(或线程)中访问它们.我建议您在后台继续获取所需的数据,但是当需要更新UIWebView时,请在主线程中进行.你可以这样做:或者您可以创建一个方法来更新UIWebView上的数据,并使用以下方法从后台线程调用它:这将确保您从正确的线程访问UIWebView.希望这可以帮助.

  10. XCode 3.2 Ruby和Python模板

    在xcode3.2下,我的ObjectiveCPython/Ruby项目仍然可以打开更新和编译,但是你无法创建新项目.鉴于xcode3.2中缺少ruby和python的所有痕迹(即创建项目并添加新的ruby/python文件),是否有一种简单的方法可以再次安装模板?我发现了一些关于将它们复制到某个文件夹的信息,但我似乎无法让它工作,我怀疑文件夹的位置已经改变为3.2.解决方法3.2中的应用程序模板

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部