python中的多进程

进程

进程和程序的区别:

编写完毕的代码,在没有运行的时候,称之为程序

正在运行着的代码,就成为进程

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

进程——资源分配的基本单位 

线程——是CPU调度的最小单位.

fork子进程(linux上,不能跨平台在windows)

 

 

res = os.fork() 它有两个返回值,是两次分别返回,也就是一次返回一个,不是一次返回两个,主进程的返回值是大于0的,而且每次和每次的值是不一样的,而子进程的返回值是等于0的。这样操作系统就能区分主进程和子进程了

 

1、父子进程执行的先后顺序 ,没有规律,由操作系统决定(调度算法)

2、getpid返回当前进程标识,getppid返回父进程标识,进程标识也就是进程识别码。

3、

 

总结:父进程中fork的返回值,就是刚刚创建出来的子进程的id。

  1. fork 不会等待子进程执行完在退出
     
    总结:父进程中fork的返回值,就是刚刚创建出来的子进程的id。
  2. 全局变量在多个进程中不共享
    多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响。进程可以完成多任务,但是,进程与进程之间是独立的,进程和进程之间想要实现通信,需要网络。
  3. 多个fork  
     
     
     

Process创建子进程(跨平台)

1、创建一个Process实例,用start()方法启动,进程所要执行的代码是通过target这个参数指定

 

  1. 主进程等待Process子进程先结束后才结束
    3、Process强调
    join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
    (正常情况下是主进程先执行完自己的代码再去等待子进程)
    join([timeout]):是否等待进程实例执行结束,或等待多少秒
    4、通过类创建子进程
    这个类必须继承process这个类,还需要在这个类中重写一个run方法,将来在开启这个进程的时候也就是对象.start的时候一定会去调用继承的process这个类的start方法,在这个方法中一定去调用了run方法的。
     

进程池Pool

非阻塞(并行执行):apply_async(func[, args[, kwds]])

阻塞(等待上一个进程退出才能执行下一个):apply

close():关闭Pool,使其不再接受新的任务;

terminate():不管任务是否完成,立即终止;

join():主进程阻塞,等待子进程的退出,必须在close或terminate之后使用;

 

 

优点:

进程池可以避免创建和销毁进程本身的额外开销,提高进程的运行效率进程对象的复用。

没有任务时子进程都睡眠在该工作队列上,当有新的任务到来时,主进程将任务添加到工作队列中。

多种方式的比较

 

 

孤儿进程、僵尸进程和守护进程

1.孤儿进程

如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这是子进程的父进程就是init进程(1号进程).其实还是很好理解的  

fork

2、僵尸进程

如果一个进程已经终止了,但是其父进程还没有获取其状态,那么这个进程就称之为僵尸进程.僵尸进程还会消耗一定的系统资源,并且还保留一些概要信息供父进程查询子进程的状态一旦父进程得到想要的信息,僵尸进程就会结束.

怎么才能避免僵尸进程

子进程退出的同时会给父进程发送一个SIGCHILD信号。 

Signal()函数的第一个函数是Linux支持的信号,第二个参数是对信号的操作 ,是系统默认还是忽略或捕获

signal(SIGCHLD,SIG_IGN)是选择对子程序终止信号选择忽略,这是僵尸进程就是交个内核自己处理,并不会产生僵尸进程.

3、守护进程

守护进程就是在后台运行,不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务.习惯上守护进程的名字通常以d结尾(sshd),但这些不是必须的.

  ps -aux | grep ssh

 

多任务或者单任务分为两种:

IO密集型的任务 (适合多线程,协程)

  1. 涉及到网络、磁盘IO的任务都是IO密集型任务。
    有阻塞的状态,就是不会一直运行CPU(中间就一个等待状态,就告诉CPU 等待状态,这个就叫IO密集型),例如:sleep 状态等
    2、特点:CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。
    3、对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。
    4、实现单核CPU上运行单进程却能实现多任务的并发。该种任务Python(执行效率相对较低)比较适合。 

计算密集型的任务(多进程)

1、特点:要进行大量的计算,消耗CPU资源。比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。

 

2、计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

 

3、计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。

进程间通信——Queue队列

进程与进程之间它们默认是没有关联的,它不能完成一个数据的共享,解决的其中之一方法就是队列( 其他方法:命名管道,无名管道,共享内存,网络socket)。

默认进程池大小等于CPU核心数

 

 

线程

  1. 主线程会等待所有的子线程结束后才结束,线程的执行顺序,由操作系统负责调度
  2. 线程共享全局变量 线程里面的局部变量各是各的。
     
     
    200 万 bug的出现原因:线程争抢CPU资源(单核cpu)
    问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。
    3、进程线程比较:
  1. 定义的不同
    进程是系统进行资源分配和调度的一个独立单位.
    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
  2. 区别
    一个程序至少有一个进程,一个进程至少有一个线程.
    线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
    进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
    线程不能够独立执行,必须依存在进程中
  3. 优缺点
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
     
    4、避免全局变量被修改
    全局变量:g_flag
    互斥锁 :互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
     
    锁的好处:
    确保了某段关键代码只能由一个线程从头到尾完整地执行
    锁的坏处:
    阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
    由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
    避免死锁
    设置加锁顺序 设置加锁时限  死锁检测

协程

  1. 协程是在一个进程里面或是一个线程里面,将任务分成了多份,也是完成多任务、并发的一种方式。
  2. 协程的底层就是生成器
    协程其实可以认为是比线程更小的执行单元,自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。
    3、协程和线程差异
    线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
    4、优点
  1. 无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能
  2. 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
    协程的缺点:

  无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

 

 

 

Python多进程模块通过提供一个简单直观的API,允许在多个进程之间划分工作。通过使用多进程模块,可以在同一Python脚本上同时运行不同的进程。每个进程都有自己独立的进程ID,可以使用os.getpid()函数获取当前进程的ID。 下面是一个使用多进程模块的简单示例:首先,我们导入multiprocessing模块,并定义了两个函数print_square和print_cube,分别用于打印给定数字的平方和立方。然后,我们创建了两个进程p1和p2,分别调用print_square和print_cube函数。最后,我们通过调用start()方法开启进程,join()方法等待进程完成,并打印最后的完成消息。 另一个示例展示了在同一Python脚本上运行多个进程的概念。我们定义了两个worker函数,分别打印当前进程的ID。然后,我们创建了两个进程p1和p2,并分别调用worker1和worker2函数。我们还可以通过调用p1.pid和p2.pid来获取进程的ID。最后,我们使用join()方法等待进程完成,并检查进程是否处于活动状态。 综上所述,Python多进程模块提供了一个方便的方式来在同一脚本上运行不同的进程,并且每个进程都有自己独立的进程ID。可以使用这些进程来并行执行不同的任务,以提高程序的效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Python 多进程](https://blog.csdn.net/a883774913/article/details/125373953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值