对Python中进程概念的理解(1)

本文介绍了多任务的概念及其实现原理,并详细解析了在Python中如何利用多进程进行并发编程,包括fork()函数的使用、multiprocessing模块的功能及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多任务

多任务:简单地说,就是操作系统可以同时运行多个任务。

1、一个cpu同一个时刻只能执行一个任务,因为切换速度非常快,感觉是多任务
2、操作系统已经设置好cpu的使用权如何分配,自己写的代码无权干涉
3、任务调度有很多算法,如:1)优先级调度 2)时间轮转 等…

程序和进程

  • 编写完毕的代码,在没有运行的时候,称之为程序
  • 正在运行着的代码,就成为进程

进程,除了包含代码以外,还有需要运行的环境等,所以和程序是有区别的。

fork()函数

当程序执行到os.fork()时,操作系统会创建一个新的进程(子进程),然后复制父进程的所有信息到子进程中。

fork函数,只在Unix/Linux/Mac上运行,windows不可以

父进程和子进程都会从fork()函数中得到一个返回值,在子进程中这个值一定是0,而父进程中是子进程的 id号。

子进程永远返回0,而父进程返回子进程的ID。

  • getpid():获得该进程的ID
  • getppid():获得父进程的ID

多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响。
进程
父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法。

multiprocessing

由于Windows没有fork调用,而Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。
multiprocessing模块提供了一个Process类来代表一个进程对象。

from multiprocessing import Process
import os


# 子进程要执行的代码
def run_proc(name):
    print('子进程运行中,name= %s ,pid=%d...' % (name, os.getpid()))


if __name__ == '__main__':
    print('父进程 %d.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('子进程将要执行')
    p.start()
    p.join()
    print('子进程已结束')

代码运行结果:
运行结果
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

Process语法结构如下:

Process([group [, target [, name [, args [, kwargs]]]]])

target:表示这个进程实例所调用对象
args:表示调用对象的位置参数元组
kwargs:表示调用对象的关键字参数字典
name:为当前进程实例的别名
group:大多数情况下用不到

Process类常用方法:

is_alive():判断进程实例是否还在执行
join([timeout]):是否等待进程实例执行结束,或等待多少秒
start():启动进程实例(创建子进程)
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法
terminate():不管任务是否完成,立即终止

Process类常用属性:

name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数
pid:当前进程实例的PID值

这里写图片描述
1、p = Process(target=run_proc, args=(‘test’,))初始化状态
2、p.start() 就绪状态,一旦获取使用cpu使用权运行,运行状态
3、运行过程中,cpu可能切换走,变成阻塞状态,阻塞状态结束后变成就绪状态,等待获取cpu使用权
4、直到进程的功能函数运行完毕,进程死亡

如果进程中有sleep、input、join也是阻塞状态

创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象。

from multiprocessing import Process
from time import sleep
import random
import os


class Sing(Process):
    def run(self):
        for i in range(3):
            print("Sing...%d...%d" % (i, os.getpid()))
            sleep(random.random())


class Dance(Process):
    def run(self):
        for i in range(3):
            print("Dance...%d...%d" % (i, os.getpid()))
            sleep(random.random())


sing = Sing()
sing.start()

dance = Dance()
dance.start()

sleep(random.random())
print("game over...")

代码运行结果:
运行结果

两种方式的对比

1、方法
2、继承类

继承类是以面向对象考虑这个事的,所以业务逻辑复杂,建议使用继承类,更好理解

<think>嗯,用户现在问的是Python中线程和进程概念和使用方法。之前他们问过关于CAPL脚本中timeNow()函数的时间单位转换问题,可能是在做嵌入式系统或者汽车电子相关的开发,比如使用CANoe工具。现在转到了Python的多线程和多进程,可能是想优化他们的脚本性能,或者处理并行任务。 首先,我需要回顾一下线程和进程的基本概念进程是程序的一次执行,拥有独立的内存空间,而线程是进程内的执行单元,共享同一进程的内存。Python由于GIL(全局解释器锁)的存在,多线程在CPU密集型任务上可能不如多进程有效,但在I/O密集型任务中还是有优势的。 用户可能想知道两者的区别,以及在什么情况下使用哪种方法。他们可能在实际项目中遇到了性能瓶颈,需要并行处理来加速任务,比如数据处理、网络请求或者文件操作。需要解释清楚GIL的影响,以及如何根据任务类型选择线程或进程。 接下来,使用方法是重点。要给出具体的代码示例,比如threading和multiprocessing模块的基本用法,创建线程和进程的方式,如何传递参数,以及如何同步线程(比如锁机制)。还有线程池和进程池的使用,比如concurrent.futures模块,这样可以简化代码并提高效率。 另外,用户可能对线程和进程之间的通信和资源共享机制感兴趣。进程间通信可能需要队列或管道,而线程间可以直接共享变量,但需要注意线程安全。需要提到常见的问题,比如死锁、竞态条件,以及如何避免它们。 最后,应用场景的对比很重要。比如,如果是处理大量计算,用进程;如果是I/O等待多的任务,用线程。结合之前的回答,用户可能有嵌入式背景,所以可能需要处理硬件交互或实时数据,这时候线程可能更合适,但如果是数据分析,可能需要进程来利用多核CPU。 还要注意用户的代码示例是否正确,是否容易理解。可能需要提醒一些注意事项,比如守护线程、子进程的启动方法(spawn、fork等),以及跨平台的兼容性问题。确保回答结构清晰,步骤明确,帮助他们逐步解决问题。</think>好的!以下是关于 **Python中线程与进程** 的详细介绍,包含核心概念、使用方法和实际场景对比: --- ### **1. 核心概念对比** | **特性** | **线程 (Thread)** | **进程 (Process)** | |------------------|--------------------------------------------|--------------------------------------------| | **资源隔离性** | 共享进程内存空间 | 独立内存空间,需通过IPC通信 | | **创建开销** | 低(约1MB内存) | 高(约10MB内存) | | **GIL影响** | 受全局解释器锁限制(CPU密集型任务并行度低) | 完全绕过GIL(可真正并行) | | **适用场景** | I/O密集型任务(文件、网络操作) | CPU密集型任务(计算、数据处理) | --- ### **2. 线程的使用方法** #### **基本示例:threading模块** ```python import threading import time def task(name): print(f"线程 {name} 启动") time.sleep(2) print(f"线程 {name} 结束") # 创建线程 t1 = threading.Thread(target=task, args=("A",)) t2 = threading.Thread(target=task, args=("B",)) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() ``` #### **关键方法** - `Lock()`:解决资源竞争 ```python lock = threading.Lock() with lock: # 临界区代码 ``` - `Event()`:线程间信号通知 ```python event = threading.Event() event.wait() # 阻塞等待 event.set() # 触发事件 ``` --- ### **3. 进程的使用方法** #### **基本示例:multiprocessing模块** ```python from multiprocessing import Process import os def compute_square(n): print(f"进程 {os.getpid()} 计算 {n}^2") return n*n if __name__ == "__main__": p1 = Process(target=compute_square, args=(3,)) p2 = Process(target=compute_square, args=(4,)) p1.start() p2.start() p1.join() p2.join() ``` #### **进程间通信(IPC)** - **队列(Queue)**: ```python from multiprocessing import Queue q = Queue() q.put(data) # 发送 data = q.get() # 接收 ``` - **管道(Pipe)**: ```python conn1, conn2 = Pipe() conn1.send(data) data = conn2.recv() ``` --- ### **4. 高效工具:线程池/进程池** #### **concurrent.futures模块** ```python from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # I/O密集型用线程池 with ThreadPoolExecutor(max_workers=4) as executor: futures = [executor.submit(task, i) for i in range(10)] # CPU密集型用进程池 with ProcessPoolExecutor() as executor: results = executor.map(compute_square, [1,2,3,4]) ``` --- ### **5. GIL的影响与选择策略** #### **性能对比公式** - **CPU密集型任务加速比**: $$ S = \frac{T_{\text{单线程}}}{T_{\text{多进程}}} \approx \text{CPU核心数} $$ - **I/O密集型任务加速比**: $$ S = \frac{T_{\text{单线程}}}{T_{\text{多线程}}} \approx \frac{\text{I/O等待时间}}{\text{CPU时间}} $$ #### **决策树** ``` 是否需要并行计算? ├─ 是 → 用多进程(绕过GIL) └─ 否 → 是否涉及I/O等待? ├─ 是 → 用多线程 └─ 否 → 单线程即可 ``` --- ### **6. 实际场景案例** #### **场景1:Web爬虫(I/O密集型)** ```python # 使用线程池加速下载 def download(url): response = requests.get(url) return len(response.content) with ThreadPoolExecutor(8) as executor: urls = ["http://example.com" for _ in range(100)] results = list(executor.map(download, urls)) ``` #### **场景2:图像处理(CPU密集型)** ```python # 使用进程池并行处理 def process_image(img_path): img = cv2.imread(img_path) return cv2.resize(img, (256,256)) with ProcessPoolExecutor() as executor: image_paths = ["img1.jpg", "img2.jpg", ...] processed = list(executor.map(process_image, image_paths)) ``` --- ### **7. 注意事项** 1. **线程安全**:共享资源(如文件、全局变量)必须加锁 2. **僵尸进程**:确保调用`join()`或使用`with`语句管理进程 3. **跨平台差异**:Windows系统需`if __name__ == "__main__":`保护入口 4. **调试难度**:多进程调试更复杂,建议使用日志记录 --- 如果需要更深入的特定场景分析(如异步协程与线程/进程的结合使用),可以进一步探讨! 🚀
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值