当前位置:首页 » 编程语言 » python进程同步

python进程同步

发布时间: 2022-12-18 04:35:51

python中的进程-实战部分

如果想了解进程 可以先看一下这一篇 python中的进程-理论部分

python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。

multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。

创建进程的类

参数介绍:

group参数未使用,值始终为None

target表示调用对象,即子进程要执行的任务

args表示调用对象的位置参数元组,args=(1,2,'tiga',)

kwargs表示调用对象的字典,kwargs={'name':'tiga','age':18}

name为子进程的名称

方法介绍:

p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法

p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True

p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

属性介绍:

注意:在windows中Process()必须放到# if __name__ == '__main__':下

创建并开启子进程的两种方式

方法一:


方法二:

有了join,程序不就是串行了吗???

terminate与is_alive

name与pid

② python进程间通信怎么理解

在2.6才开始使用
multiprocessing 是一个使用方法类似threading模块的进程模块。允许程序员做并行开发。并且可以在UNIX和Windows下运行。
通过创建一个Process 类型并且通过调用call()方法spawn一个进程。

一个比较简单的例子:
#!/usr/bin/env python

from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print 'hello ',name
print os.getppid() #取得父进程ID
print os.getpid() #取得进程ID
process_list = []
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()

进程间通信:
有两种主要的方式:Queue、Pipe
1- Queue类几乎就是Queue.Queue的复制,示例:
#!/usr/bin/env python

from multiprocessing import Process,Queue
import time
def f(name):
time.sleep(1)
q.put(['hello'+str(name)])
process_list = []
q = Queue()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()
for i in range(10):
print q.get()
2- Pipe 管道
#!/usr/bin/env python

from multiprocessing import Process,Pipe
import time
import os

def f(conn,name):
time.sleep(1)
conn.send(['hello'+str(name)])
print os.getppid(),'-----------',os.getpid()
process_list = []
parent_conn,child_conn = Pipe()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(child_conn,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
for p in range(10):
print parent_conn.recv()
Pipe()返回两个连接类,代表两个方向。如果两个进程在管道的两边同时读或同时写,会有可能造成corruption.

进程间同步
multiprocessing contains equivalents of all the synchronization primitives from threading.
例如,可以加一个锁,以使某一时刻只有一个进程print
#!/usr/bin/env python

from multiprocessing import Process,Lock
import time
import os

def f(name):
lock.acquire()
time.sleep(1)
print 'hello--'+str(name)
print os.getppid(),'-----------',os.getpid()
lock.release()
process_list = []
lock = Lock()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()

进程间共享状态 Sharing state between processes
当然尽最大可能防止使用共享状态,但最终有可能会使用到.
1-共享内存
可以通过使用Value或者Array把数据存储在一个共享的内存表中
#!/usr/bin/env python

from multiprocessing import Process,Value,Array
import time
import os

def f(n,a,name):
time.sleep(1)
n.value = name * name
for i in range(len(a)):
a[i] = -i
process_list = []
if __name__ == '__main__':
num = Value('d',0.0)
arr = Array('i',range(10))
for i in range(10):
p = Process(target=f,args=(num,arr,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
print num.value
print arr[:]
输出:
jimin@Jimin:~/projects$ python pp.py
81.0
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
'd'和'i'参数是num和arr用来设置类型,d表示一个双精浮点类型,i表示一个带符号的整型。
更加灵活的共享内存可以使用multiprocessing.sharectypes模块

Server process
Manager()返回一个manager类型,控制一个server process,可以允许其它进程通过代理复制一些python objects
支持list,dict,Namespace,Lock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value,Array
例如:
#!/usr/bin/env python

from multiprocessing import Process,Manager
import time
import os

def f(d,name):
time.sleep(1)
d[name] = name * name
print d
process_list = []
if __name__ == '__main__':
manager = Manager()
d = manager.dict()
for i in range(10):
p = Process(target=f,args=(d,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
print d
输出结果:
{2: 4}
{2: 4, 3: 9}
{2: 4, 3: 9, 4: 16}
{1: 1, 2: 4, 3: 9, 4: 16}
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 8: 64}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
Server process managers比共享内存方法更加的灵活,一个单独的manager可以被同一网络的不同计算机的多个进程共享。
比共享内存更加的缓慢

使用工作池Using a pool of workers
Pool类代表 a pool of worker processes.
It has methods which allows tasks to be offloaded to the worker processes in a few different ways.

③ 简述python进程,线程和协程的区别

协程多与线程进行比较
1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
2) 线程进程都是同步机制,而协程则是异步
3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

④ Python入门系列(十二)——GUI+多进程

话说,python做图形界面并不明智,效率并不高。但在某些特殊需求下还是需要我们去使用,所以python拥有多个第三方库用以实现GUI,本章我们使用python基本模块tkinter进行学习,因为需求并不大,所以不做太多拓展。
继续改写上一章的IP查询系统(= =,要玩烂了),首先略改下IpWhere.py以备调用~

然后使用tkinter模块进行图形界面的实现,调用预编译的IpWhere模块 :

额,太丑了,但基本实现我们小小的需求,在以后的py学习中,我们再涉及其他的第三方模块,此处就当是入门了解吧。

十分抱歉把这么重要的内容放在最后,要不是大佬指点,此次学习可能就要错过多进程的问题了。
Unix系统提供了forx,python可借助os模块调用,从而实现多进程,然而windows系统并不具备,所以我们选择python内置的multiprocessing多进程模块进行学习。

首先我们借助直接调用多进程来改写下我们在多线程章节用到的例子!

显然,这么写实在太蠢了,如果我们的任务量巨大,这并不合适。所以我们引入了进程池的概念,使用进程池进行改写:

在此,我们可以看到所有进程是并发执行的,同样,我们在多线程章节就讲过,主进程的结束意味着程序退出,所以我们需要借助join()方法堵塞进程。

我们知道线程共享内存空间,而进程的内存是独立的,同一个进程的线程之间可以直接交流,也就带来了线程同步的苦恼,这个我们在多线程章节已经讲过了;而两个进程想通信,则必须通过一个中间代理来实现,即我们接下来的内容:进程间通信。

进程之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。我们接下来就以Queue的方式进行学习。

Queue.Queue是进程内非阻塞队列,multiprocess.Queue是跨进程通信队列,前者是各自私有,后者是各子进程共有。

还有一个在后者基础上进行封装的multiprocess.Manager.Queue()方法,如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息: RuntimeError: Queue objects should only be shared between processes through inheritance.

接下来我们就借助进程池来进行多进程操作的改写,感谢大佬一路辅导。

我们可以看到两个子线程先执行,然后一个子线程单独执行,此处有意而为之,让大家更清晰的了解队列的使用。期间有一处我们放弃使用jion()方法堵塞,而是自己写了个循环堵塞,大家根据自己习惯来就好。

话说,真的没人吐槽么?上面的例子从需求上来讲,完全就不需要多线程好不好!emmmm,我们来点实力拓展,写一个有智商的多线程脚本,顺便结合上一节的web来一个综合篇,随便找个现实需求吧!

emmm,比如我们来到当当网买书,搜一下我们想要的书籍,发现!!太多了!!真J2乱!!看不过来!!不想翻页!!直接告诉我哪个便宜、哪个牛逼好不好!!

简单看下这个url:
http://search.dangdang.com/?key=渗透测试&ddsale=1&page_index=2
其中ddsale参数代表当当自营,page_index代表页数,key代表搜索内容,我们本次的变量只有页数。

所以我们构造请求的url为:
'http://search.dangdang.com/?key=渗透测试&ddsale=1&page_index='+str(page)
如果修改的内容不使用str字符串转化,会收到如下报错:
TypeError: can only concatenate str (not "int") to str
然后我们看一下页面内容的分布情况,本次我们关心卖什么书,卖多少钱?

对应的编写我们的正则匹配规则,当然了,有更简便的第三方库可以帮我们处理,但为了更好的形成流程性认识,我们这里依然使用正则。
我们对应我们需要的书籍名称和当前价格匹配如下:
<a title=" (.*?)" ddclick=
<span class="search_now_price">¥(.*?)</span>
那么,思路理清了,我们就开始使用多线程来写我们的小系统~

然后我们去查看一下我们的结果文件~

现在这个小系统具备的功能就是根据用户需要选择要检索的书籍,然后整理下名称和价格,开了10个线程,如果小伙伴pc给力的话可以继续加。简单的异常处理机制和界面交互,基本满足日常所需。

⑤ python 多进程

基于官方文档:
https://docs.python.org/zh-cn/3/library/multiprocessing.html
日乐购,刚才看到的一个博客,写的都不太对,还是基于官方的比较稳妥
我就是喜欢抄官方的,哈哈

通常我们使用Process实例化一个进程,并调用 他的 start() 方法启动它。
这种方法和 Thread 是一样的。

上图中,我写了 p.join() 所以主进程是 等待 子进程执行完后,才执行 print("运行结束")
否则就是反过来了(这个不一定,看你的语句了,顺序其实是随机的)例如:

主进加个 sleep

所以不加join() ,其实子进程和主进程是各干各的,谁也不等谁。都执行完后,文件运行就结束了

上面我们用了 os.getpid() 和 os.getppid() 获取 当前进程,和父进程的id
下面就讲一下,这两个函数的用法:
os.getpid()
返回当前进程的id
os.getppid()
返回父进程的id。 父进程退出后,unix 返回初始化进程(1)中的一个
windows返回相同的id (可能被其他进程使用了)
这也就解释了,为啥我上面 的程序运行多次, 第一次打印的parentid 都是 14212 了。
而子进程的父级 process id 是调用他的那个进程的 id : 1940

视频笔记:
多进程:使用大致方法:

参考: 进程通信(pipe和queue)

pool.map (函数可以有return 也可以共享内存或queue) 结果直接是个列表

poll.apply_async() (同map,只不过是一个进程,返回结果用 xx.get() 获得)

报错:

参考 : https://blog.csdn.net/xiemanR/article/details/71700531

把 pool = Pool() 放到 if name == " main ": 下面初始化搞定。
结果:

这个肯定有解释的

测试多进程计算效果:
进程池运行:

结果:

普通计算:

我们同样传入 1 2 10 三个参数测试:

其实对比下来开始快了一半的;
我们把循环里的数字去掉一个 0;
单进程:

多进程:

两次测试 单进程/进程池 分别为 0.669 和 0.772 几乎成正比的。
问题 二:
视图:
post 视图里面

Music 类:

直接报错:

写在 类里面也 在函数里用 self.pool 调用也不行,也是相同的错误。

最后 把 pool = Pool 直接写在 search 函数里面,奇迹出现了:

前台也能显示搜索的音乐结果了

总结一点,进程这个东西,最好 写在 直接运行的函数里面,而不是 一个函数跳来跳去。因为最后可能 是在子进程的子进程运行的,这是不许的,会报错。
还有一点,多进程运行的函数对象,不能是 lambda 函数。也许lambda 虚拟,在内存??

使用 pool.map 子进程 函数报错,导致整个 pool 挂了:
参考: https://blog.csdn.net/hedongho/article/details/79139606
主要你要,对函数内部捕获错误,而不能让异常抛出就可以了。

关于map 传多个函数参数
我一开始,就是正常思维,多个参数,搞个元祖,让参数一一对应不就行了:

报错:

参考:
https://blog.csdn.net/qq_15969343/article/details/84672527
普通的 process 当让可以穿多个参数,map 却不知道咋传的。
apply_async 和map 一样,不知道咋传的。

最简单的方法:
使用 starmap 而不是 map

结果:
子进程结束
1.8399453163146973
成功拿到结果了

关于map 和 starmap 不同的地方看源码

关于apply_async() ,我没找到多参数的方法,大不了用 一个迭代的 starmap 实现。哈哈

关于 上面源码里面有 itertools.starmap
itertools 用法参考:
https://docs.python.org/zh-cn/3/library/itertools.html#itertool-functions

有个问题,多进程最好不要使用全部的 cpu , 因为这样可能影响其他任务,所以 在进程池 添加 process 参数 指定,cpu 个数:

上面就是预留了 一个cpu 干其他事的

后面直接使用 Queue 遇到这个问题:

解决:
Manager().Queue() 代替 Queue()

因为 queue.get() 是堵塞型的,所以可以提前判断是不是 空的,以免堵塞进程。比如下面这样:
使用 queue.empty() 空为True

⑥ python多线程怎样同步

锁机制
�6�9�6�9threading的Lock类,用该类的acquire函数进行加锁,用realease函数进行解锁

import threading
import time

class Num:
def __init__(self):
self.num = 0
self.lock = threading.Lock()
def add(self):
self.lock.acquire()#加锁,锁住相应的资源
self.num += 1
num = self.num
self.lock.release()#解锁,离开该资源
return num

n = Num()
class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item
def run(self):
time.sleep(2)
value = n.add()#将num加1,并输出原来的数据和+1之后的数据
print(self.item,value)

for item in range(5):
t = jdThread(item)
t.start()
t.join()#使线程一个一个执行
�6�9�6�9当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”(参见多线程的基本概念)。
�6�9�6�9直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

信号量
�6�9�6�9信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用了release方法将内部计数器更新到大于1位置。

import threading
import time
class Num:
def __init__(self):
self.num = 0
self.sem = threading.Semaphore(value = 3)
#允许最多三个线程同时访问资源

def add(self):
self.sem.acquire()#内部计数器减1
self.num += 1
num = self.num
self.sem.release()#内部计数器加1
return num

n = Num()
class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item
def run(self):
time.sleep(2)
value = n.add()
print(self.item,value)

for item in range(100):
t = jdThread(item)
t.start()
t.join()
条件判断
�6�9�6�9所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。
�6�9�6�9它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。

"""
一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1.
"""

"""
使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有
wait, notify, notifyAll 方法。
"""

import threading
import queue,time,random

class Goods:#产品类
def __init__(self):
self.count = 0
def add(self,num = 1):
self.count += num
def sub(self):
if self.count>=0:
self.count -= 1
def empty(self):
return self.count <= 0

class Procer(threading.Thread):#生产者类
def __init__(self,condition,goods,sleeptime = 1):#sleeptime=1
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
cond.acquire()#锁住资源
goods.add()
print("产品数量:",goods.count,"生产者线程")
cond.notifyAll()#唤醒所有等待的线程--》其实就是唤醒消费者进程
cond.release()#解锁资源
time.sleep(self.sleeptime)

class Consumer(threading.Thread):#消费者类
def __init__(self,condition,goods,sleeptime = 2):#sleeptime=2
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
time.sleep(self.sleeptime)
cond.acquire()#锁住资源
while goods.empty():#如无产品则让线程等待
cond.wait()
goods.sub()
print("产品数量:",goods.count,"消费者线程")
cond.release()#解锁资源

g = Goods()
c = threading.Condition()

pro = Procer(c,g)
pro.start()

con = Consumer(c,g)
con.start()
同步队列
�6�9�6�9put方法和task_done方法,queue有一个未完成任务数量num,put依次num+1,task依次num-1.任务都完成时任务结束。

import threading
import queue
import time
import random

'''
1.创建一个 Queue.Queue() 的实例,然后使用数据对它进行填充。
2.将经过填充数据的实例传递给线程类,后者是通过继承 threading.Thread 的方式创建的。
3.每次从队列中取出一个项目,并使用该线程中的数据和 run 方法以执行相应的工作。
4.在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号。
5.对队列执行 join 操作,实际上意味着等到队列为空,再退出主程序。
'''

class jdThread(threading.Thread):
def __init__(self,index,queue):
threading.Thread.__init__(self)
self.index = index
self.queue = queue

def run(self):
while True:
time.sleep(1)
item = self.queue.get()
if item is None:
break
print("序号:",self.index,"任务",item,"完成")
self.queue.task_done()#task_done方法使得未完成的任务数量-1

q = queue.Queue(0)
'''
初始化函数接受一个数字来作为该队列的容量,如果传递的是
一个小于等于0的数,那么默认会认为该队列的容量是无限的.
'''
for i in range(2):
jdThread(i,q).start()#两个线程同时完成任务

for i in range(10):
q.put(i)#put方法使得未完成的任务数量+1

⑦ python同时打开几个程序默认运行哪一个

操作系统的作用
隐藏丑陋复杂的硬件接口,提供良好的抽象接口
管理、调度进程,并且将多个进程对硬件的竞争变得有序
2. 多道技术产生背景

针对单核,实现并发
现在的主机一般是多核,那么每个核都会利用多道技术
有 4 个 cpu,运行于 cpu1 的某个程序遇到 io 阻塞,会等到 io 结束再重新调度
会被调度到 4 个 cpu 中的任意一个,具体由操作系统调度算法决定
3. 多道技术空间上的复用:如内存中同时有多道程序

4. 多道技术时间上的复用

复用一个 cpu 的时间片
注意,遇到 io 切,占用 cpu 时间过长也切
核心在于切之前将进程的状态保存下来
这样才能保证下次切换回来时,能基于上次切走的位置继续运行
进程的概念
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动
进程是操作系统动态执行的基本单元
在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元
进程与程序的区别
程序是指令和数据的有序集合,是一个静态的概念。程序可以作为一种软件资料长期存在,是永久的
进程是程序在处理机上的一次执行过程,它是一个动态的概念。进程是有一定生命期的,是暂时的
5. 注意:同一个程序执行两次,就会在操作系统中出现两个进程。所以可以同时运行一个软件,分别做不同的事情也不会混乱,比如可以打开两个Pycharm做不同的事

6. 进程调度

要想多个进程交替运行,操作系统必须对这些进程进行调度
这个调度也不是随即进行的,而是需要遵循一定的法则
由此就有了进程的调度算法:先来先服务调度算法、短作业优先调度算法、时间片轮转法、多级反馈队列
并行和并发
并行是指在一个时间点上,有多个进程在被 cpu 计算,比如赛跑,两个人都在不停的往前跑
并发是指资源有限的情况下,在一个时间段上,有多个进程在被 cpu 计算,交替轮流使用资源
并行与并发的区别
并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器
并发是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个 session
进程的三状态
在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态
就绪
运行
阻塞
2. 举例说明什么是 argv,什么是阻塞

import sys
print(sys.argv)

# 运行结果:
['G:/course_select/进程的概念.py']

# argv 指参数
# sys.argv 是 Python 解释器在运行的时候传递进来的参数

# 首先在cmd输入以下信息:
python G:/course_select/进程的概念.py
# 打印结果:
['G:/course_select/进程的概念.py']

# 然后在cmd中切换路径到G盘,接着输入 python course_select/进程的概念.py
# 打印结果:
['course_select/进程的概念.py']

# 接着,再在cmd中输入:python course_select/进程的概念.py 123 abc
# 打印结果:
['course_select/进程的概念.py', '123', 'abc']

# 因此,以下程序不能在编辑器里运行,只能在 cmd 里面使用 Python 运行本文件
# 然后要在后面加上 aaa bbb
# 就像上面的 python course_select/进程的概念.py 123 abc 一样
if sys.argv[1] == "aaa" and sys.argv[2] == "bbb":
print("登录成功")
else:
print("登录失败")
exit()
print(666)

# 而如果使用input(),其实就是一种阻塞
3. 进程的三状态图

.png
同步异步
同步:形象的说,一件事的执行必须依赖另一件事的结束,强调的是顺序性
异步: 形象的说,两件事情可以同时进行
注意:同步异步和并行、并发没关系
阻塞:等待,比如 input sleep recv accept recvfrom
非阻塞:不等待,start/terminate 都是非阻塞的
阻塞与非阻塞主要是从程序(线程)等待消息通知时的状态角度来说的
可以分为四类:
同步阻塞
异步阻塞
同步非阻塞
异步非阻塞
start/terminate 都是非阻塞的
进程模块
跟进程相关的基本都在这个模块里:multiprocessing
父进程与子进程的对比分析
父进程,比如运行本文件
子进程,运行 Process(target=func).start()
父进程与子进程数据隔离
主进程等待子进程结束之后再结束
子进程和主进程之间默认是异步的
from multiprocessing import Process
import time

def func():
time.sleep(1)
print(666)

if __name__ == "__main__":
# 开启了一个新的进程,在这个新的进程里执行的 func()
Process(target=func).start()
time.sleep(1)
# 主进程
print(777)

# 777
# 666
# 运行结果仔细观察发现有异步的效果
# 也就是说,主进程和新的进程同时执行
3. 上面的示例中为什么要有 if __name__ == "__main__"?其实这是 windows 操作系统开启子进程的方式问题

4. 继续深入

import time
import os
from multiprocessing import Process

def func():
time.sleep(1)
print(666, os.getpid(), os.getppid())

if __name__ == "__main__":
# 代码执行到这里并不代表开启了子进程
p = Process(target=func)
# 开启了一个子进程,并执行func()
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 主进程运行的结果
777 12340 1636
# 子进程运行的结果
666 7604 12340

# 由上面两行结果可以得出:
# 利用 os.getpid() 证明两个进程不一样
# 另外每次运行,os.getpid() 结果都不一样
# 但是,12340 是主进程的 id,7604 是子进程的 id
# 1636 是 Pycharm 的 id,排列特点不变
5. 开启多个相同的子进程示例

import time
import os
from multiprocessing import Process

def func():
time.sleep(3)
print(666, os.getpid(), os.getppid())

if __name__ == "__main__":
for i in range(10):
p = Process(target=func)
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 这里需要注意一点:Python 程序一直都是逐行执行
# 但是因为这里设置了时间延迟,因此会先执行主程序的代码
# 运行结果:
777 29006 3833 # 暂停 2s 后再有下面的结果
666 29007 29006
666 29009 29006
666 29008 29006
666 29010 29006
666 29013 29006
666 29011 29006
666 29012 29006
666 29014 29006
666 29016 29006
666 29015 29006

# 观察结果发现主进程只运行了一次
# 然后剩下的全是一个子进程重新运行的结果
# 主进程运行完不会结束,它会等子进程全部运行结束
# 注意变量 p 拿到的是最后一个子进程的 id
6. 开启多个不同的子进程示例

import time
import os
from multiprocessing import Process

def func():
time.sleep(2)
print(666, os.getpid(), os.getppid())

def func2():
print(111)

if __name__ == "__main__":
for i in range(3):
p = Process(target=func)
p.start()
for i in range(2):
p = Process(target=func2)
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 运行程序时仔细观察结果显示顺序:
111
111
777 29316 3833
666 29319 29316
666 29317 29316
666 29318 29316
7. 给子进程传参示例

from multiprocessing import Process

def func(name):
print(666, name)

if __name__ == "__main__":
p = Process(target=func,args=(777,)) # 注意是一个元组
p.start()

import time
from multiprocessing import Process

def func(num, name):
time.sleep(1)
print(num, "hello", name)

if __name__ == "__main__":
for i in range(10):
p = Process(target=func, args=(i, "abc"))
p.start()
print("主进程")

# 运行结果:
666 777
主进程
0 hello abc
2 hello abc
1 hello abc
3 hello abc
5 hello abc
4 hello abc
6 hello abc
7 hello abc
8 hello abc
9 hello abc

# 多运行几次,发现子进程并不是完全按顺序运行的
# 比如上面先出结果 2 hello abc,再出结果 1 hello abc
8. 子进程可以有返回值吗:不能有返回值,因为子进程函数中的返回值无法传递给父进程

import time
from multiprocessing import Process

def func():
time.sleep(3)
print("这是子进程,3s后才运行")

if __name__ == "__main__":
Process(target=func).start()
print("主进程")

# 运行结果:
主进程
这是子进程,3s后才运行

# 主进程会默认等待子进程结束之后才结束
# 因为父进程要负责回收子进程占用的操作系统资源
相关资源:Python多进程写入同一文件的方法_python多进程写入同意文件-其它...
文章知识点与官方知识档案匹配
Python入门技能树首页概览
194693 人正在系统学习中
点击阅读全文
打开CSDN,阅读体验更佳

Python多进程(一)进程及进程池_程序员-夏天的博客
print("主进程结束") 通过上述代码我们发现,multiprocessing.Process帮我们创建一个子进程,并且成功运行,但是我们发现,在子进程还没执行完的时候主进程就已经死了,那么这个子进程在主进程结束后就是一个孤儿进程,那么我们可以让主进程等待...
Python多进程之Process、Pool、Lock、Queue、Event、Semaphore、Pipe_大 ...
1. Python创建进程类Process python的multiprocessing模块提供了一个创建进程的类Precess,其创建有以下两种方法: 创建Process类的实例,并指向目标函数和传递参数 自定义一个类并继承Process类,重写__init__()和run()方法 ...
python两个进程同时开启只运行了一个_二十二、 深入Python的进程和线程(上篇)...
“@Author: Runsen”进程(Process)和线程(Thread)都是操作系统中的基本概念,它们之间有一些优劣和差异,那么在Python中如何使用进程和线程?CPU计算机的核心是CPU,它承担了计算机的所有计算任务,CPU就像一个工厂,时刻在运行着,而操作系统管理着计算机,负责任务的调度、资源的分配和管理。进程进程是指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据...
继续访问
python启动多个进程_Python多处理:只有一个进程正在运行
由于注释表明您希望使用初始化程序和initargs参数传递featureVector.在Unix类型的系统上,这将导致大量的性能提升(即使selLabel中只有1个项目),因为该值将使用os.fork基本上免费传递给子进程.否则,每次调用foo时,featureVector都将被父进程pickle,通过管道传递并由子进程进行unpickled.这将花费很长时间,并且基本上将序列化所有子进程,因为它...
继续访问
python多进程多线程,多个程序同时运行_陈逸飞_p的博客_pyth...
python 模块应用 开发工具 pycharm 实现方法 多任务的实现可以用进程和线程来实现 进程—> 线程---> 多任务应用 多进程操作 比如下载多个文件, 利用cpu 资源 提高效率 多任务: 同一时间执行多个任务, 比如windows操作系统 执行...
python多进程单例_Python多线程处理实例详解【单进程/多进程】
python — 多线程处理 1、一个进程执行完后,继续下一个进程 root@72132server:~# cd /root/python/multiprocess/ root@72132server:~/python/multiprocess# ls multprocess.py root@72132server:~/python/multiprocess# cat multprocess...
系统编程__2__父子进程的创建和回收
系统编程 这里写的是对于小白来说更多的了解系统编程的文章,有写的不对的地方还恳请各位大佬指出错误,小编一定会多多采纳[手动多谢]。 那么,上一次我们稍微了解了一下关于系统编程的一些主要内容[没有看到的童鞋还请去上一篇文章稍微复习一下噢]。 这节课,我们先来想一想,我们为什么要学系统编程呢?原因很简单,我们要充分的利用CPU的性能,CPU和我们人类不太一样,我们人类大多数情况下,在同一时间,只能完成一件事,而CPU作为无数科学家的心血当然不会这么简单,CPU能够同时进行多个进程,这里的进程我们可以理解成任务,
继续访问
android 10 system/core无法打印log问题
1.关闭重定向 system/core/init/util.cpp --- a/init/util.cpp +++ b/init/util.cpp @@ -454,7 +454,7 @@ static void InitAborter(const char* abort_message) { // SetStdioToDevNull() must be called again in second stage init. void SetStdioToDevNull(char** argv) { ...
继续访问
Python多进程1 一个多进程实例_BBJG_001的博客
下执行,job('主进程step1###')p1=mp.Process(target=job,args=('新进程>>>',))# 创建一个进程# 注意当只有一个参数的时候,一定要在参数后面加一个逗号,因为args需要是一个可以迭代的参量p1.start()# 开始执行新进程# p...
热门推荐 python多进程多线程,多个程序同时运行
python 多线程 多进程同时运行 多任务要求 python 基础语法 python 文件目录操作 python 模块应用 开发工具 pycharm 实现方法 多任务的实现可以用进程和线程来实现 进程—> 线程----> 多任务应用 多进程操作 比如下载多个文件, 利用cpu 资源 提高效率 多任务: 同一时间执行多个任务, 比如windows操作系统 执行方式有两种( 表现形式 ) 并发 在单核cpu中: 在一段时间内交替执行多个任务, 例如单核cpu 处理多任务, 操作系统让各个任务交
继续访问
fork()函数
多进程通信 fork()函数
继续访问
(1/7)Electron教程(一)什么是 Electron,由来、适用场景 和 Electron 的环境搭建(1/7)
最近自己有个小的需求,是做一个能编辑本地特定文本的工具,需要跨平台, Windows 和 macOS,这样,如果用原生开发的话,Windows 就要用c#macOS 就要用swift,学习成本高,并且学完用处也不是很大。我本身是前端开发的,发现了这个electron能满足我的需求,跨平台运行,内部是 js 驱动的,简直就是如鱼得水。顺便把学习的经历写出来,分享需要的人,我会按标题序号渐进式地编写内容。electron。...
继续访问

fork()详解
<一>: fork()函数用来创建新的进程,它的特点是调用一次返回两次( 在原来的进程中返回新进程的 PID(新进程的 PID 肯定不等于 0), 在新进程中返回为 0.) 函数原型:pid_t fork(void); pid_t getpid(); 获取当前进程的 pid 值。 pid_t getppid(); 获取当前进程的父进程 pid 值。 图一 如图一所...
继续访问
fork()函数详解
目录 1.基本了解: 2.fork函数的了解: 3.僵死进程: 1.基本了解: 一个进程,包括代码、数据和分配给进程的资源。fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1。 为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值: 1)在父进程中,fork返回新创建子进程的进程...
继续访问

Electron在Windows下的环境搭建
Electron作为一种用javascript写桌面程序的开发方式,现在已经被大众接受。下面就介绍如何在windows(>win7)下快速搭建Electron开发环境。 1. nodejs 的安装 从nodejs 下载最新版本的windows安装程序进行安装,我下载的是v6.9.1,安装时一路默认即可,这个安装会把nodejs和npm配置到系统PATH中,这样在命令行的任何位置都可以直接...
继续访问
python多线程pool_Python mutiprocessing多线程池pool操作示例
本文实例讲述了Python mutiprocessing多线程池pool操作。分享给大家供大家参考,具体如下:python — mutiprocessing 多线程 pool脚本代码:root@72132server:~/python/multiprocess# lsmultiprocess_pool.py multprocess.pyroot@72132server:~/python/multi...
继续访问
最新发布 python入门开发学习笔记之守护进程
本节重点 了解守护进程的概念 本节时长需控制在5分钟内 一 守护进程 主进程创建子进程,然后将该进程设置成守护自己的进程,守护进程就好比崇祯皇帝身边的老太监,崇祯皇帝已死老太监就跟着殉葬了。 关于守护进程需要强调两点: 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children 如果我们有两个任务需要并发执行,那么开一个主进程和一个子进程分
继续访问
用python进行多进程编程时,只有主进程可以运行,子进程貌似没有运行是什么原因?
找了半天,原来是这个原因!这是因为multiprocessing模块在交互模式是不支持的,在 cmd 里头输入 python xxx.py 来运行起来,你就可以看到子进程的执行了。
继续访问
linux中fork() 函数详解
fork入门知识 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了...
继续访问
Windows版 Node.js 安装详解以及Electron安装
Windows Node.js 安装详解以及Electron安装详解,示例版本:node v10.15.0/npm6.4.1 介绍: 简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执...
继续访问

Electron 简介
本教程我们来学习 Electron 的基础知识,下面我们先来学习一下什么是 Electron。 Electron是什么 Electron 是是 GitHub 开发的一个开源框架。它允许使用 Node.js(作为后端)和 Chromium(作为前端)完成桌面 GUI 应用程序的开发。 Electron 可以用于构建具有 HTML、CSS、JavaScript 的跨平台桌面应用程序,它通过将 Chromium 和 node.js 合同一个运行的环境中来实现这一点,应用程序可以打包到 Mac、Windows 和
继续访问

Election的优缺点
优点 原生的接口(菜单、消息提醒、系统托盘等)。 上手难度低。能够使用react、vue等前端框架,能方便地迁移前端组件,构建出漂亮的桌面应用。 方便热更新 调试和测试方便 Electron使用node.js。因此,您可以导入Chrome应用程序中不容易使用的许多模块 Electron文档要好得多,尽管它是一个更年轻的平台 缺点 不适合开发轻量级的应用。即使一个electron的项目框架,也包含chromium内核,打包完接近200G。 相比c++开发的桌面应用,性能远远不如后者。 启动速
继续访问
[electron]终极奥义 五千字教程丢给你
前言 本文包含打包、自动更新、简易API、调试、进程通信等相关知识点,内容较多,可能会引起不适,请酌情查看(手动滑稽)。 electron 简介 electron是由Github开发,是一个用Html、css、JavaScript来构建桌面应用程序的开源库,可以打包为Mac、Windows、Linux系统下的应用。 electron是一个运行时环境,包含Node和Chromium,可以理解成把we...
继续访问
深入理解Java中的wait() 方法
使用场景 当某个线程获取到锁后,发现当前还不满足执行的条件,就可以调用对象锁的wait方法,进入等待状态。 直到某个时刻,外在条件满足了,就可以由其他线程通过调用notify()或者notifyAll()方法,来唤醒此线程。 这篇文章将侧重于讨论wait()方法对于线程状态的影响,以及被唤醒后线程的状态变更。 条件 只有已经获取锁的线程,才可以调用锁的wait方法,否则会抛出异常IllegalMonitorStateException。 比如下面的代码,A获得了锁后,主动调用wait方法释放锁和
继续访问

用Electron开发桌面应用的避坑指南(文末送书)
送一波高质量Web开发图书,送5本书籍,随你挑。抽奖规则见本文最后!抽奖规则见本文最后!抽奖规则见本文最后!如今,Electron 领域发生了重大的变革,Electron 版本更新换代极快...
继续访问

python多进程只有一个进程在执行
python两个进程同时开启只运行了一个。

⑧ python可以多进程吗

想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。

开辟子进程
multiprocessing中提供了Process类来生成进程实例

Process([group [, target [, name [, args [, kwargs]]]]])
group分组,实际上不使用
target表示调用对象,你可以传入方法的名字
args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可
kwargs表示调用对象的字典
name是别名,相当于给这个进程取一个名字
先来个小例子:

# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time

def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime()) #获取当前进程号和正在运行是的时间
time.sleep(wTime) #等待(休眠)
n += 1

if __name__ == "__main__":
p = Process(target=run_proc, args=(2,)) #申请子进程
p.start() #运行进程
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
运行结果:

Parent process run. subProcess is 30196
Parent process end,Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:23 2017
subProcess 30196 run, Mon Mar 27 11:20:25 2017

根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸( zombie)进程。

通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

有什么办法可以避免僵尸进程呢?
这里介绍进程的一个属性 deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon = true,看看效果。

# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time

def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
time.sleep(wTime)
n += 1

if __name__ == "__main__":
p = Process(target=run_proc, args=(2,))
p.daemon = True #加入daemon
p.start()
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
执行结果:

Parent process run. subProcess is 31856
Parent process end,Mon Mar 27 11:40:10 2017

这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?
这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码

# -*- coding:utf-8 -*-
from multiprocessing import Process, Pool
import os
import time

def run_proc(wTime):
n = 0
while n < 3:
print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
time.sleep(wTime)
n += 1

if __name__ == "__main__":
p = Process(target=run_proc, args=(2,))
p.daemon = True
p.start()
p.join() #加入join方法
print "Parent process run. subProcess is ", p.pid
print "Parent process end,{0}".format(time.ctime())
执行结果:

subProcess 32076 run, Mon Mar 27 11:46:07 2017
subProcess 32076 run, Mon Mar 27 11:46:09 2017
subProcess 32076 run, Mon Mar 27 11:46:11 2017
Parent process run. subProcess is 32076
Parent process end,Mon Mar 27 11:46:13 2017

这样所有的进程就能顺利的执行了。

⑨ Python多进程运行——Multiprocessing基础教程2

上篇文章简单介绍了multiprocessing模块,本文将要介绍进程之间的数据共享和信息传递的概念。

在多进程处理中,所有新创建的进程都会有这两个特点:独立运行,有自己的内存空间。

我们来举个例子展示一下:

这个程序的输出结果是:

在上面的程序中我们尝试在两个地方打印全局列表result的内容:

我们再用一张图来帮助理解记忆不同进程间的数据关系:

如果程序需要在不同的进程之间共享一些数据的话,该怎么做呢?不用担心,multiprocessing模块提供了Array对象和Value对象,用来在进程之间共享数据。

所谓Array对象和Value对象分别是指从共享内存中分配的ctypes数组和对象。我们直接来看一个例子,展示如何用Array对象和Value对象在进程之间共享数据:

程序输出的结果如下:

成功了!主程序和p1进程输出了同样的结果,说明程序中确实完成了不同进程间的数据共享。那么我们来详细看一下上面的程序做了什么:

在主程序中我们首先创建了一个Array对象:

向这个对象输入的第一个参数是数据类型:i表示整数,d代表浮点数。第二个参数是数组的大小,在这个例子中我们创建了包含4个元素的数组。

类似的,我们创建了一个Value对象:

我们只对Value对象输入了一个参数,那就是数据类型,与上述的方法一致。当然,我们还可以对其指定一个初始值(比如10),就像这样:

随后,我们在创建进程对象时,将刚创建好的两个对象:result和square_sum作为参数输入给进程:

在函数中result元素通过索引进行数组赋值,square_sum通过 value 属性进行赋值。

注意:为了完整打印result数组的结果,需要使用 result[:] 进行打印,而square_sum也需要使用 value 属性进行打印:

每当python程序启动时,同时也会启动一个服务器进程。随后,只要我们需要生成一个新进程,父进程就会连接到服务器并请求它派生一个新进程。这个服务器进程可以保存Python对象,并允许其他进程使用代理来操作它们。

multiprocessing模块提供了能够控制服务器进程的Manager类。所以,Manager类也提供了一种创建可以在不同流程之间共享的数据的方法。

服务器进程管理器比使用共享内存对象更灵活,因为它们可以支持任意对象类型,如列表、字典、队列、值、数组等。此外,单个管理器可以由网络上不同计算机上的进程共享。

但是,服务器进程管理器的速度比使用共享内存要慢。

让我们来看一个例子:

这个程序的输出结果是:

我们来理解一下这个程序做了什么:首先我们创建了一个manager对象

在with语句下的所有行,都是在manager对象的范围内的。接下来我们使用这个manager对象创建了列表(类似的,我们还可以用 manager.dict() 创建字典)。

最后我们创建了进程p1(用于在records列表中插入一条新的record)和p2(将records打印出来),并将records作为参数进行传递。

服务器进程的概念再次用下图总结一下:

为了能使多个流程能够正常工作,常常需要在它们之间进行一些通信,以便能够划分工作并汇总最后的结果。multiprocessing模块支持进程之间的两种通信通道:Queue和Pipe。

使用队列来回处理多进程之间的通信是一种比较简单的方法。任何Python对象都可以使用队列进行传递。我们来看一个例子:

上面这个程序的输出结果是:

我们来看一下上面这个程序到底做了什么。首先我们创建了一个Queue对象:

然后,将这个空的Queue对象输入square_list函数。该函数会将列表中的数平方,再使用 put() 方法放入队列中:

随后使用 get() 方法,将q打印出来,直至q重新称为一个空的Queue对象:

我们还是用一张图来帮助理解记忆:

一个Pipe对象只能有两个端点。因此,当进程只需要双向通信时,它会比Queue对象更好用。

multiprocessing模块提供了 Pipe() 函数,该函数返回由管道连接的一对连接对象。 Pipe() 返回的两个连接对象分别表示管道的两端。每个连接对象都有 send() 和 recv() 方法。

我们来看一个例子:

上面这个程序的输出结果是:

我们还是来看一下这个程序到底做了什么。首先创建了一个Pipe对象:

与上文说的一样,该对象返回了一对管道两端的两个连接对象。然后使用 send() 方法和 recv() 方法进行信息的传递。就这么简单。在上面的程序中,我们从一端向另一端发送一串消息。在另一端,我们收到消息,并在收到END消息时退出。

要注意的是,如果两个进程(或线程)同时尝试从管道的同一端读取或写入管道中的数据,则管道中的数据可能会损坏。不过不同的进程同时使用管道的两端是没有问题的。还要注意,Queue对象在进程之间进行了适当的同步,但代价是增加了计算复杂度。因此,Queue对象对于线程和进程是相对安全的。

最后我们还是用一张图来示意:

Python的multiprocessing模块还剩最后一篇文章:多进程的同步与池化

敬请期待啦!

⑩ 一文带你读懂Python中的进程

进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行,即正在运行的程序,是系统进行资源分配和调度的基本单位,进程是对正在运行程序的一个抽象,在早期面向进程设计的计算机结构中,进程是程序的基本执行实体,在当代面向线程设计的计算机结构中,进程是线程的容器,线程是执行的实体。进程的概念起源于操作系统,是操作系统最核心的概念,操作系统的其他所有内容都是围绕进程的概念展开的。

在早期计算机中可以利用的cpu只有一个,为了充分利用CPU性能,提高用户操作体验,出现了多道技术。将一个单独的cpu虚拟成多个cpu(多道技术:时间多路复用和空间多路复用+硬件上支持隔离),即使在一个单核CPU也能保证支持(伪)并发的能力。如果没有进程的抽象,现代计算机将不复存在。

狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。

广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

操作系统的作用:

隐藏复杂的硬件接口,提供良好的抽象接口。

管理、调度进程,使多个进程对硬件的竞争变得有序。

多道技术:针对早期单核CPU,实现多个程序的并发执行,现在的主机一般是多核,每个核都会利用多道技术,如有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,重新调度是可能会被调度到4个cpu中的任意一个,具体由操作系统调度算法决定。

多道技术的主要特性如下:

(1)空间上的复用:内存中可以同时有多道程序。

(2)物理隔离:多个程序在内存中都有各自独立的内存空间,互不影响。

(3)时间上的复用:多个程序在操作系统的调度算法下,在不同的时间段内分别占有CPU资源。

需要注意的是如果一个进程长时间占用CPU资源,操作系统会强制将CPU资源分配给其它在就绪队列中的程序,避免一个程序长时间占有CPU资源,导致其它程序无法运行。

相关推荐:《Python视频教程》

关于进程的一些概念:

第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码,数据区域存储变量和进程执行期间使用的动态分配的内存,堆栈区域存储着活动过程调用的指令和本地变量。

第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统将程序加载到内存),它才能成为一个活动的实体,我们称其为进程。

进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。

进程的特性:

动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。

并发性:任何进程都可以同其他进程一起并发执行

独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

结构特征:进程由程序、数据和进程控制块三部分组成。

多个不同的进程可以包含相同的程序,一个程序在不同的数据集里就构成不同的进程,能得到不同的结果,但是执行过程中,程序不能发生改变。

进程与程序的区别:

程序是指令和数据的有序集合,是对指令、数据及其组织形式的描述,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。

程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。

进程的调度:

要想多个进程交替运行,操作系统必须对这些进程进行调度,这个调度也不是随机进行的,而是需要遵循一定的法则,由此就有了进程的调度算法。

1、先来先服务算法

先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。FCFS算法比较有利于长作业(进程),而不利于短作业(进程)。由此可知,本算法适合于CPU繁忙型作业,而不利于I/O繁忙型的作业(进程)。

2、短作业优先调度算法

短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调度,也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是被估算出来的。

3、时间片轮转法

时间片轮转(Round Robin,RR)法的基本思路是让每个进程在就绪队列中的等待时间与享受服务的时间成比例。在时间片轮转法中,需要将CPU的处理时间分成固定大小的时间片,例如,几十毫秒至几百毫秒。如果一个进程在被调度选中之后用完了系统规定的时间片,但又未完成要求的任务,则它自行释放自己所占有的CPU而排到就绪队列的末尾,等待下一次调度。同时,进程调度程序又去调度当前就绪队列中的第一个进程。

显然,轮转法只能用来调度分配一些可以抢占的资源。这些可以抢占的资源可以随时被剥夺,而且可以将它们再分配给别的进程。CPU是可抢占资源的一种。但打印机等资源是不可抢占的。由于作业调度是对除了CPU之外的所有系统硬件资源的分配,其中包含有不可抢占资源,所以作业调度不使用轮转法。

在轮转法中,时间片长度的选取非常重要。首先,时间片长度的选择会直接影响到系统的开销和响应时间。如果时间片长度过短,则调度程序抢占处理机的次数增多。这将使进程上下文切换次数也大大增加,从而加重系统开销。反过来,如果时间片长度选择过长,例如,一个时间片能保证就绪队列中所需执行时间最长的进程能执行完毕,则轮转法变成了先来先服务法。时间片长度的选择是根据系统对响应时间的要求和就绪队列中所允许最大的进程数来确定的。

在轮转法中,加入到就绪队列的进程有3种情况:

(1)一种是分给它的时间片用完,但进程还未完成,回到就绪队列的末尾等待下次调度去继续执行。

(2)另一种情况是分给该进程的时间片并未用完,只是因为请求I/O或由于进程的互斥与同步关系而被阻塞。当阻塞解除之后再回到就绪队列。

(3)第三种情况就是新创建进程进入就绪队列。

如果对这些进程区别对待,给予不同的优先级和时间片从直观上看,可以进一步改善系统服务质量和效率。例如,我们可把就绪队列按照进程到达就绪队列的类型和进程被阻塞时的阻塞原因分成不同的就绪队列,每个队列按FCFS原则排列,各队列之间的进程享有不同的优先级,但同一队列内优先级相同。这样,当一个进程在执行完它的时间片之后,或从睡眠中被唤醒以及被创建之后,将进入不同的就绪队列。

多级反馈队列:

前面介绍的各种用作进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程,而且如果并未指明进程的长度,则短进程优先和基于进程长度的抢占式调度算法都将无法使用。

而多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。在采用多级反馈队列调度算法的系统中,调度算法的实施过程如下所述。

(1) 应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时间片长一倍,……,第i+1个队列的时间片要比第i个队列的时间片长一倍。

(2) 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n 队列便采取按时间片轮转的方式运行。

(3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。

热点内容
dirt5需要什么配置 发布:2024-05-20 06:02:58 浏览:542
怎么把电脑锁上密码 发布:2024-05-20 05:19:09 浏览:985
安卓为什么连上wifi后没有网络 发布:2024-05-20 05:17:50 浏览:419
安卓usb在设置哪里 发布:2024-05-20 05:03:03 浏览:187
绥化编程 发布:2024-05-20 04:59:44 浏览:991
基本原理和从头计算法 发布:2024-05-20 04:50:32 浏览:30
配置情况指的是什么 发布:2024-05-20 04:48:14 浏览:497
那个程序用来编译源文件 发布:2024-05-20 04:46:45 浏览:551
小程序需要数据库吗 发布:2024-05-20 04:35:14 浏览:338
链接sqlserver 发布:2024-05-20 04:27:53 浏览:210