线程与进程的区别与联系:操作系统入门详解(含 Python 示例)
、先搞懂进程与线程到底是什么通俗类比官方定义1.1 生活化类比快速建立认知如果把计算机的操作系统比作一个大型工厂进程就是工厂里的一个个独立车间。每个车间有自己专属的生产资源比如机器、原材料车间之间相互隔离不会共用资源一个车间出问题不会直接影响其他车间。线程是车间里的工人。同一个车间进程里的多个工人线程共享车间的所有资源机器、原材料他们协同完成车间的生产任务工人之间沟通成本低但一旦某个工人操作失误可能会影响整个车间的运行。1.2 官方定义精准理解核心进程Process进程是操作系统进行资源分配和调度的基本单位。简单来说当你打开一个软件比如微信、浏览器操作系统就会为这个软件创建一个或多个进程每个进程都会占用独立的内存空间、CPU时间片、文件句柄等系统资源。比如你在Windows系统中打开“任务管理器”看到的“微信.exe”“chrome.exe”都是一个个独立的进程关闭进程就意味着终止对应的程序运行。线程Thread线程是操作系统进行CPU调度和执行的基本单位也被称为“轻量级进程”。一个进程可以包含多个线程这些线程共享进程的内存空间、全局变量、文件资源等同时每个线程有自己独立的程序计数器、栈空间和寄存器状态。比如你用浏览器一个进程同时浏览网页、下载文件、播放视频这些操作其实是由浏览器进程内的多个线程分别完成的。二、核心线程与进程的区别10个关键维度为了让你清晰对比我整理了最核心的10个区别维度从资源、调度、开销等方面全面梳理对比维度进程线程资源分配操作系统分配资源的基本单位不分配独立资源共享所属进程的资源CPU调度调度的最小单位间接调度和执行的最小单位直接内存空间拥有独立的内存空间共享进程的内存空间仅私有栈空间创建/销毁开销大需分配内存、资源等小仅需分配栈空间等少量资源切换开销大需保存/恢复整个进程状态小仅保存/恢复线程私有数据通信方式复杂需IPC管道、套接字、共享内存等简单直接读写共享变量即可独立性高进程间相互隔离互不影响低同一进程内线程共享资源一个线程崩溃可能导致整个进程崩溃并发性可并发执行但开销高并发执行效率更高是实现并发的主流方式所有权拥有独立的进程IDPID拥有线程IDTID依赖所属进程的PID系统支持所有操作系统均支持部分早期操作系统不支持现代系统均支持关键区别解读资源层面进程是“资源容器”线程是“容器里的执行单元”。比如一个Java程序运行时JVM会创建一个主进程进程内的main线程、GC线程、用户创建的线程都共享JVM的堆内存、方法区等资源。开销层面创建一个进程的开销约是创建线程的几十倍甚至上百倍因为进程需要申请独立的内存空间、初始化资源表等而线程仅需初始化少量私有数据即可。稳定性层面进程的“隔离性”是把双刃剑——隔离性高意味着一个进程崩溃不会影响其他进程比如浏览器某个标签页崩溃不会导致整个浏览器关闭但通信成本高线程共享资源则通信方便但一个线程的非法操作比如内存越界可能导致整个进程崩溃。三、不可忽视线程与进程的联系区别之外二者的联系更是理解操作系统运行逻辑的关键线程依赖进程存在线程不能独立于进程运行任何线程都必须属于某个进程进程是线程的“容器”。没有进程线程就没有资源可以使用也无法被操作系统调度。进程的执行依赖线程一个进程至少包含一个线程称为“主线程”没有线程的进程只是一个“空的资源容器”无法执行任何任务。比如Java程序的main方法对应的就是主线程启动程序时先创建进程再执行主线程。资源共享与隔离的平衡操作系统通过进程实现资源隔离避免程序之间相互干扰通过线程实现资源共享降低程序内部的通信成本二者结合既保证了系统稳定性又提升了执行效率。调度协同操作系统的调度器会同时管理进程和线程——先选择要执行的进程再在进程内选择要执行的线程最终将CPU时间片分配给线程。四、实战用代码直观理解进程与线程Python示例理论不如实战我用Python编写了简单易懂的代码示例分别演示进程的创建、线程的创建以及二者的核心区别资源隔离/共享、创建开销。前置条件确保你的环境安装了Python3.6无需额外安装依赖示例使用Python内置的multiprocessing和threading模块。示例1创建并运行进程资源隔离import multiprocessing import os # 定义进程执行的函数 def process_task(num): # 获取当前进程的ID和父进程ID print(f子进程ID: {os.getpid()}, 父进程ID: {os.getppid()}) # 进程间变量不共享修改的是子进程内的局部变量 num 10 print(f子进程内num的值: {num}) if __name__ __main__: # 主进程ID print(f主进程ID: {os.getpid()}) # 定义一个全局变量 num 5 print(f主进程初始num的值: {num}) # 创建子进程 p multiprocessing.Process(targetprocess_task, args(num,)) # 启动进程 p.start() # 等待子进程执行完成 p.join() # 主进程的num值未被修改进程间资源隔离 print(f主进程最终num的值: {num})代码运行结果主进程ID: 12345 主进程初始num的值: 5 子进程ID: 12346, 父进程ID: 12345 子进程内num的值: 15 主进程最终num的值: 5代码解读os.getpid()获取当前进程IDos.getppid()获取父进程ID能清晰看到主进程和子进程是两个独立的进程子进程内修改了num的值但主进程的num未变证明进程间资源隔离子进程无法直接修改主进程的变量。示例2创建并运行线程资源共享import threading import time # 定义全局变量线程共享 shared_num 0 # 创建锁避免多线程竞争导致数据错乱 lock threading.Lock() # 定义线程执行的函数 def thread_task(name, add_num): global shared_num # 加锁保证操作原子性 with lock: temp shared_num # 模拟耗时操作放大线程竞争效果 time.sleep(0.1) shared_num temp add_num print(f线程{name}执行后shared_num的值: {shared_num}) if __name__ __main__: print(f主线程初始shared_num的值: {shared_num}) # 创建两个线程 t1 threading.Thread(targetthread_task, args(A, 5)) t2 threading.Thread(targetthread_task, args(B, 3)) # 启动线程 t1.start() t2.start() # 等待所有线程执行完成 t1.join() t2.join() print(f主线程最终shared_num的值: {shared_num})代码运行结果主线程初始shared_num的值: 0 线程A执行后shared_num的值: 5 线程B执行后shared_num的值: 8 主线程最终shared_num的值: 8代码解读两个线程共享全局变量shared_num修改后主线程能看到最终结果证明线程共享进程的资源加入lock锁是为了避免“线程安全问题”——如果不加锁两个线程同时修改shared_num可能导致数据错乱比如最终结果不是8而是3或5这也是线程共享资源带来的常见问题。示例3对比进程与线程的创建开销import multiprocessing import threading import time # 定义空任务仅用于测试创建开销 def empty_task(): pass # 测试进程创建开销 def test_process_cost(): start_time time.time() # 创建100个进程并启动 processes [] for i in range(100): p multiprocessing.Process(targetempty_task) processes.append(p) p.start() # 等待所有进程完成 for p in processes: p.join() end_time time.time() print(f创建100个进程耗时: {end_time - start_time:.2f} 秒) # 测试线程创建开销 def test_thread_cost(): start_time time.time() # 创建100个线程并启动 threads [] for i in range(100): t threading.Thread(targetempty_task) threads.append(t) t.start() # 等待所有线程完成 for t in threads: t.join() end_time time.time() print(f创建100个线程耗时: {end_time - start_time:.2f} 秒) if __name__ __main__: test_process_cost() test_thread_cost()代码运行结果参考创建100个进程耗时: 3.56 秒 创建100个线程耗时: 0.02 秒代码解读从耗时能明显看出创建进程的开销远大于线程——这也是为什么日常开发中实现并发优先选择线程而非进程的核心原因。http://www.cdxkxl.com/news/45621五、实际应用场景什么时候用进程什么时候用线程理解了区别和联系最终要落地到实际开发中不同场景的选择直接影响程序性能http://www.cdxkxl.com/news/72815.1 适合用进程的场景http://www.cdxkxl.com/news/9128需要高隔离性的任务比如服务器上同时运行多个独立的应用程序Web服务、数据库服务每个应用用独立进程避免一个应用崩溃影响其他应用http://www.cdxkxl.com/news/89291CPU密集型任务且多核CPU比如大数据计算、视频编码使用多进程可以充分利用多核CPUPython的GIL锁导致多线程无法利用多核CPU密集型任务需用多进程跨机器通信的场景进程可以通过网络套接字等方式实现跨机器通信线程仅能在同一台机器的同一进程内通信。5.2 适合用线程的场景http://www.cdxkxl.com/news/9371I/O密集型任务比如网络请求、文件读写、数据库操作这类任务大部分时间在等待线程切换开销小能充分利用CPU空闲时间程序内部的并发操作比如一个应用内同时处理用户输入、数据计算、界面刷新用多线程可以避免界面卡顿通信频繁的任务线程间共享内存通信成本低适合需要频繁交换数据的场景比如生产消费模型。5.3 特殊场景进程线程结合实际开发中很多大型应用会采用“多进程多线程”的架构比如Nginx服务器主进程负责管理配置、监听端口多个子进程负责处理请求每个子进程内又有多个线程处理具体的连接既保证了隔离性又提升了并发效率。六、常见误区这些坑一定要避开误区1多线程一定比单线程快不一定如果是CPU密集型任务比如纯计算在Python中由于GIL锁的存在多线程反而可能因为切换开销导致速度更慢此时应使用多进程。只有I/O密集型任务多线程才能体现优势。误区2线程共享资源可以随意修改线程共享资源时多个线程同时修改同一个变量会导致“线程安全问题”数据错乱、死锁等必须通过锁互斥锁、条件锁、信号量等机制保证线程安全。误区3进程崩溃不会影响其他进程理论上是但如果多个进程共享了系统核心资源比如显卡、内存一个进程异常占用大量资源也可能导致其他进程卡顿甚至崩溃。七、总结核心知识点回顾核心定位进程是资源分配的基本单位线程是CPU执行的基本单位线程依赖进程存在进程的执行依赖线程。核心区别进程有独立资源、开销大、隔离性高线程共享进程资源、开销小、隔离性低通信更简单。应用选择CPU密集型高隔离性选进程I/O密集型内部并发选线程大型应用可结合二者使用。通过本文的讲解和代码实战相信你已经彻底理解了线程与进程的区别与联系。其实核心逻辑很简单进程是“独立的车间”线程是“车间里的工人”操作系统通过这两个概念的配合实现了资源的高效分配和任务的并发执行。无论是面试还是开发掌握这些核心知识点就能轻松应对大部分相关问题。总结核心概念进程是资源分配单位独立车间线程是CPU执行单位车间工人线程依赖进程存在且共享进程资源关键区别进程开销大、隔离性高、通信复杂线程开销小、共享资源、通信简单
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2465403.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!