博客
关于我
并发编程小结
阅读量:439 次
发布时间:2019-03-06

本文共 2840 字,大约阅读时间需要 9 分钟。

Python并发编程实践指南

1. 线程与进程基础

1.1 线程与进程的定义

线程是程序执行的最小单元,进程是资源分配的最小单位。每个进程可以包含多个线程,而每个线程在执行时会独占CPU。与进程不同,线程共享进程的地址空间和资源,这使得线程切换更加高效。

1.2 GIL锁的作用

在Python中,Global Interpreter Lock(GIL)用于限制同一进程中同时执行的线程数量。GIL在执行100条指令后切换线程,确保线程安全。默认情况下,GIL锁会在每个进程中限制同时运行的线程数量。

1.3 线程创建的意义

线程的主要作用是利用多核CPU的优势实现并行执行。通过创建多个线程,可以同时处理多个任务,提高系统性能。

1.4 进程与线程的区别

  • 进程:资源分配的最小单位,拥有独立的地址空间。
  • 线程:程序执行的最小单位,共享进程的地址空间。

线程切换成本低,但线程间通信需要同步机制。进程间通信则需要通过 IPC(进程间通信)实现。

2. 多线程与多进程的选择

2.1 多线程适用场景

  • IO密集型任务:由于GIL锁的限制,多线程在IO操作上效率较高。
  • 计算密集型任务:多线程无法充分利用多核优势,通常选择多进程。

2.2 多进程适用场景

  • 计算密集型任务:多进程可以更好地利用多核资源。
  • IO密集型任务:虽然多进程在IO操作上效率较低,但在内存分配和资源隔离方面更具优势。

3. 协程与并发优化

3.1 协程的定义

协程是一种微线程,由程序员手动控制线程切换。与线程不同,协程是在代码块之间进行切换,而不是逐行执行。

3.2 协程的优缺点

  • 优点:协程可以在不等待IO操作的情况下进行切换,提升并发性能。
  • 缺点:协程本身无法实现真正的并发,性能可能低于多线程或多进程。

4. IO多路复用技术

4.1 IO多路复用的作用

IO多路复用用于检测多个socket是否有数据到来或连接请求。它支持三种模式:select、poll和epoll,适用于不同的IO调度需求。

4.2 Python中IO多路复用实现

  • select:支持最多1024个socket,使用轮询方式检测socket状态。
  • epoll:支持无限多个socket,采用回调机制实现边缘触发。

5. 异步与非阻塞编程

5.1 异步编程的概念

异步编程允许程序在执行IO操作时立即返回,并自动执行后续操作。与同步编程不同,异步操作不会阻塞当前线程。

5.2 非阻塞IO的实现

通过设置socket的非阻塞属性(setblocking(False)),可以避免等待IO操作。但需处理可能的BlockingIOError异常。

6. 协程与事件驱动框架

6.1 协程框架的优势

协程框架(如gevent)通过自动切换线程实现IO非阻塞,提升了并发性能。

6.2 事件驱动框架的特点

事件驱动框架(如Twisted)通过事件循环实现异步编程,执行完成后自动调用回调函数。

7. 并发优化方案

7.1 多进程与多线程

  • 多进程:适合计算密集型任务,资源隔离更好。
  • 多线程:适合IO密集型任务,内存占用更低。

7.2 单线程并发

单线程通过IO多路复用和非阻塞socket实现并发,适用于资源受限的环境。

8. 基于事件循环的异步编程

8.1 代码示例

import socketimport select# 创建三个socket对象并设置为非阻塞client_baidu = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_baidu.setblocking(False)client_sogou = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_sogou.setblocking(False)client_github = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_github.setblocking(False)# 初始化事件循环socket_list = [client_baidu, client_sogou, client_github]conn_list = [client_baidu, client_sogou, client_github]while True:    rlist, wlist, elist = select.select(socket_list, conn_list, [], 0.5)        for sk in wlist:        if sk == client_baidu:            sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')        elif sk == client_sogou:            sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')        else:            sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')        conn_list.remove(sk)        for sk in rlist:        chunks = []        while True:            try:                chunk = sk.recv(8096)                if not chunk:                    break                chunks.append(chunk)            except BlockingIOError:                break        body = b''.join(chunks)        print('Download complete:', body.decode('utf-8'))        sk.close()        socket_list.remove(sk)        if not socket_list:        break

8.2 协程与事件驱动的对比

  • 协程:手动控制线程切换,适合复杂的异步逻辑。
  • 事件驱动:自动处理事件,代码结构更清晰。

9. 最终总结

选择合适的并发策略(多进程、多线程、协程、单线程)取决于任务特点和资源约束。理解GIL锁的机制和IO多路复用的应用,是实现高效并发的关键。

转载地址:http://scgyz.baihongyu.com/

你可能感兴趣的文章
NLP问答系统:使用 Deepset SQUAD 和 SQuAD v2 度量评估
查看>>
NLP:使用 SciKit Learn 的文本矢量化方法
查看>>
Nmap扫描教程之Nmap基础知识
查看>>
Nmap端口扫描工具Windows安装和命令大全(非常详细)零基础入门到精通,收藏这篇就够了
查看>>
NMAP网络扫描工具的安装与使用
查看>>
NMF(非负矩阵分解)
查看>>
nmon_x86_64_centos7工具如何使用
查看>>
NN&DL4.1 Deep L-layer neural network简介
查看>>
NN&DL4.3 Getting your matrix dimensions right
查看>>
NN&DL4.8 What does this have to do with the brain?
查看>>
nnU-Net 终极指南
查看>>
No 'Access-Control-Allow-Origin' header is present on the requested resource.
查看>>
NO 157 去掉禅道访问地址中的zentao
查看>>
no available service ‘default‘ found, please make sure registry config corre seata
查看>>
no connection could be made because the target machine actively refused it.问题解决
查看>>
No Datastore Session bound to thread, and configuration does not allow creation of non-transactional
查看>>
No fallbackFactory instance of type class com.ruoyi---SpringCloud Alibaba_若依微服务框架改造---工作笔记005
查看>>
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc
查看>>
No mapping found for HTTP request with URI [/...] in DispatcherServlet with name ...的解决方法
查看>>
No mapping found for HTTP request with URI [/logout.do] in DispatcherServlet with name 'springmvc'
查看>>