用python实现Linux系统编程——进程
来源:互联网 发布:手机windows live ID 编辑:程序博客网 时间:2024/06/07 06:48
1.1多任务引入
生活中一般是多项事情同时进行,歌手唱歌、跳舞同时进行,用程序模拟唱歌、跳舞,代码如下:
import time
def sing():
forx in range(3):
print("正在唱歌。。。")
def dance():
fory in range(3):
print("正在跳舞。。。")
def main():
sing()
dance()
if __name__ =="__main__":
main()
<<15_1.py>>
但是输出的是先唱歌3次,再跳舞3次(并不是同时进行)
1.2多任务的概念
多任务:同时进行多项事务,对计算机操作系统而言,就是同时运行多个任务(程序),真正的并行多任务只能在多核CPU上实现,实际的计算任务量远超过CPU核心数,操作系统通过调度算法,将多任务分配给每个核心,单核cpu执行的时候是采用时间片轮转的方式运行多个任务
1.3进程的创建-fork
1.进程vs程序
进程:需要分配到时间片、在内存空间中、有程序代码、被CPU执行
程序:保存在磁盘上的一段代码
2.fork()
在Linux系统中可以调用系统fork()函数可以轻松创建进程
用fork()创建边唱歌、边跳舞的进程,示例代码:
import os,time
def sing():
forx in range(3):
print("正在唱歌%d"%x)
def dance():
fory in range(3):
print("正在跳舞%d"%y)
pid = os.fork()
if pid < 0:
print("fork调用失败!")
elif pid == 0:
print("进入子进程")
sing()
else:
print("进入父进程")
dance()
<<15_2.py>>
【注】os.fork()函数创建进程的时候先复制原有进程(父进程)到子进程,在父进程里返回值是创建的子进程的pid,在子进程里返回值是0,可以通过os.getpid()函数获取当前进程的pid,通过os.getppid()获取父进程的pid,调用一次,有两个返回值,fork()不能用于windows系统
示例代码:
import os
def main():
pid= os.fork()
ifpid < 0:
print("fork调用失败")
elifpid == 0:
print("进入子进程:")
print("当前进程pid=%d,父进程pid=%d"%(os.getpid(),os.getppid()))
print("在子进程中执行完毕")
else:
print("进入父进程执行")
print("当前进程的子进程pid=%d,父进程pid=%d"%(pid,os.getpid()))
print("父进程中运行完毕")
if __name__ =="__main__":
main()
<<15_3.py>>
僵尸进程产生的原因:子进程运行结束,父进程尚未结束,并且未取回收子进程的资源就形成僵尸进程,僵尸进程保留这资源信息,以便父进程查找进程结束的原因
回收僵尸进程:在子进程后面调用os.wait()函数,os.wait()会阻塞父进程,(子进程没结束,父进程不会运行)
示例代码:(用fork产生僵尸进程)
import os
def main():
pid= os.fork()
ifpid < 0:
print("fork失败!")
elifpid == 0:
whileTrue:
print("进入子进程,子进程pid=%d,父进程是%d"%(os.getpid(),os.getppid()))
else:
print("进入父进程,父进程pid=%d,子进程pid=%d"%(os.getpid(),pid))
if __name__ =="__main__":
main()
<<fork产生僵尸进程.py>>
孤儿进程:子进程还在运行,父进程已经结束,就产生了孤儿进程,变成后台进程,不阻塞bash程序,不能接受用户输入,也不会相应用户输入
在ubuntu15.04版后图形界面情况下,孤儿进程都由upstart进程来接收,并成为它们的父进程,负责回收进程资源
在早期版本或命令行下是由1号init进程接收并回收资源
示例代码:(用fork产生孤儿进程)
import os
def main():
pid= os.fork()
ifpid < 0:
print("fork失败!")
elifpid == 0:
whileTrue:
print("进入子进程,子进程pid=%d,父进程pid=%d"%(os.getpid(),os.getppid()))
else:
print("进入父进程,父进程pid=%d,子进程pid=%d"%(os.getpid(),pid))
if __name__ =="__main__":
main()
<<fork产生孤儿进程.py>>
fork产生的子进程,在父进程没结束的情况下可以输入,父进程结束后子进程就变成孤儿进程,就不能接收输入报错
process产生的子进程,都不能接受输入,输入会报错,僵尸进程可以用join()回收
1.4.多进程修改全局变量
示例代码:
# -*- coding:utf-8-*-
import os
def work_add():
forx in range(5):
globalnum
num+= 1
print("全局变量num=%d"%num)
def work_minus():
fory in range(3):
globalnum
num-= 1
print("全局变量num=%d"%num)
def main():
globalnum
num= 0
pid= os.fork()
ifpid < 0:
print("fork失败!")
elifpid == 0:
print("进入子进程")
work_add()
else:
print("进入父进程")
work_minus()
if __name__ =="__main__":
main()
<<fork修改全局变量.py>>
多进程中,每个进程中所有数据(包括全局变量)都各拥有一份,互不影响
1.5多次fork问题
2次fork示例代码:
# -*- coding:utf-8-*-
import os
pid1 = os.fork()
pid2 = os.fork()
print("pid1=%d,pid2=%d,getpid=%d,getppid=%d"%(pid1,pid2,os.getpid(),os.getppid()))
<<2次fork.py>>
fork()在父进程中返回值为产生的子进程的编号,在子进程中返回值为0,父子进程执行的顺序由操作系统的调度算法决定,不固定
1.6multiprocessing创建进程
fork()不支持windows系统,python是跨平台语言,要创建windows系统的多进程怎么办?
python内的multiprocessing模块里的Process类是一个创建多进程的类
1.Process类创建实例进程(子进程)时需要传入一个子类将要执行的函数(地址/函数名)和相应的参数,启动子进程用start方法
2.join()方法可以等待子进程运行结束后再继续往下运行,通常用于进程间的同步
Process语法结构:
Process([group[,target[,name[args[,kwargs]]]]])
- target:表示这个进程实例所调用的对象;(要执行的任务,一般是函数名)
- args:表示调用对象的参数元组;(x,)
- kwargs:表示调用对象的关键字参数字典;
- name:为当前进程实例的别名
- group:大多情况下用不到
Process类常用方法
- is_alive():判断进程实例是否还存在;
- join([timeout]):是否等待进程实例执行结束,或等待多少秒;
- start():启动进程实例(创建子进程);
- run():如果没有给定target参数,对这个对象调用start()方法是,就将执行对象中的run()方法;
- terminate():不管任务是否完成,立即终止;
Process类常用属性:
- name:当前进程实例的别名,默认为Process-N,N为从1开始递增的整数;
- pid:当前进程实例的pid值
process创建进程实例:(示例代码)
# -*- coding:utf-8-*-
from multiprocessingimport Process
import os
def work(num):
print("work进程%d开始运行,父进程为%d"%(os.getpid(),os.getppid()))
forx in range(num):
print("进程work运行%d次"%(x+1))
def main():
print("主进程%d开始运行"%os.getpid())
p= Process(target=work,args=(5,))
p.start()
p.join()
print("主进程运行结束")
if __name__ =="__main__":
main()
process创建进程实例,使用更多属性和方法:(示例代码)
# -*- coding:utf-8-*-
importos,time,random
from multiprocessingimport Process
def sing(name):
t_start= time.time()
forx in range(5):
print("进程%s开始执行,pid=%d"%(name,os.getpid()))
print("唱歌第%d次"%x)
time.sleep(random.random()*2)
t_end= time.time()
print("进程%s执行完毕,耗时%0.2f秒"%(name,t_end-t_start))
def dance(name):
t_start= time.time()
forx in range(5):
print("进程%s开始执行,pid=%d"%(name,os.getpid()))
print("跳舞第%d次"%x)
time.sleep(random.random()*2)
t_end= time.time()
print("进程%s执行完毕,耗时%0.2f秒"%(name,t_end-t_start))
def main():
p1 = Process(target=sing,args=("唱歌",))
p2 = Process(target=dance,name ="dance",args=("跳舞",))
p1.start()
p2.start()
p1.join()
p2.join()
print("p1进程运行结束,进程名:%s"%p1.name)
print("p2进程运行结束,进程名:%s"%p2.name)
if __name__ =="__main__":
main()
<<多process.py>>
1.7 Process子类创建进程
Process派生类创建子进程,自定义类通过继承Process就可以创建实例化进程
示例代码:
# -*- coding:utf-8-*-
import os,time
from multiprocessingimport Process
classMyProcess(Process):
def__init__(self,name):
Process.__init__(self)
self.name= name
defrun(self):
t_start= time.time()
print("进程%s开始运行,pid=%d"%(self.name,os.getpid()))
time.sleep(2)
t_end= time.time()
print("进程%s运行结束,耗时%0.2f秒"%(self.name,t_end-t_start))
def main():
myproc= MyProcess("myprocess")
myproc.start()
if __name__ =="__main__":
main()
<<process派生类.py>>
1.8.进程池Pool
利用multiprocessing的Process类可以动态创建进程,但是当任务量比较大的时候,创建、删除、又创建进程会消耗很多时间,利用multiprocessing模块里的Pool,可以先将一批进程创建好,执行任务的时候直接调用进程,当进程完成一项任务后又将进程返回到进程池中以备后用,可以提高工作效率
multiprocessing.Pool常用函数解析:
- apply_async(func[,args[,kwargs]]):使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个继承退出才能执行下一个进程),args为传递给func的参数列表,kwargs为传递给func的关键字参数列表;
- apply(func[,args[,kwargs]]):使用阻塞方式调用func
- close():关闭Pool,使其不再接受新的任务;
- terminate():不管任务是否完成,立即终止;
- join():主进程阻塞,等待子进程的退出,必须再close或terminate之后使用;
使用进程池完成多进程任务,示例代码:
# -*-coding:utf-8 -*-
importos,time,random
from multiprocessingimport Pool
def work(num):
t_start= time.time()
print("子进程(%d)开始执行work任务%d"%(os.getpid(),num))
time.sleep(random.random()*2)
t_end= time.time()
print("子进程(%d)完成work任务%d,耗时:%0.2f秒"%(os.getpid(),num,t_end-t_start))
def main():
po= Pool(5)
forx in range(10):
po.apply_async(work,(x,))
po.close()
po.join()
if __name__ =="__main__":
main()
<<pool.py>>
1.9进程间通信-Queue
进程之间不能共享全局变量,但是进程之间经常需要通信,python的multiprocessing模块中提供了Queue机制(队列)实现进程间的通信
Queue使用说明
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);
Queue.qsize():返回当前队列包含的消息数量;
Queue.empty():如果队列为空,返回True,反之False;
Queue.full():如果队列满了,返回True,反之False;
Queue.get([block[,timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;
2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;
Queue.get_nowait():相当Queue.get(False);
Queue.put(item,[block[,timeout]]):将item消息写入队列,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常;
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;
Queue.put_nowait(item):相当Queue.put(item,False);
Queue使用示例代码:
# -*- coding:utf-8-*-
import os,time
from multiprocessingimport Queue,Process
def writer(q,msg):
print("开始写入数据:")
forw in msg:
print(w)
ifnot q.full():
q.put(w)
else:
print("队列已满")
def reader(q):
print("开始读取消息:")
ifnot q.empty():
fory in range(q.qsize()):
r= q.get()
ifr == '#!#':
print("队列已空")
break
else:
print(r)
else:
print("队列已空")
def main():
msg = input("请输入要发送的消息(每个字以空格隔开):")
msg= list(msg.split(" "))
msg.append("#!#")
print(msg)
print("msg长度:%d"%len(msg))
qu= Queue(len(msg))
print(qu)
#po= Pool(4)
p1= Process(target = writer,args=(qu,msg))
p2= Process(target = reader,args=(qu,))
p1.start()
p1.join()
p2.start()
p2.join()
if __name__ =="__main__":
main()
<<queue1.py>>
进程池Pool里消息队列Queue
要使用Pool创建进程,就需要使用multiprocessing.Manger()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条错误信息:
RuntimeError: Queue objects should only be sharedbetween processes through inheritance.(运行时错误:Queue对象只能被通过继承产生的对象间共享)
示例代码:
# -*- coding:utf-8-*-
importtime,random,os
from multiprocessingimport Manager,Pool
defwriter(q,msg,id):
print("开始写入消息,进程%d,执行第%d部分任务"%(os.getpid(),id))
ifnot q.full():
forw in msg:
q.put(w)
else:
print("消息队列已满")
def reader(q,id):
print("开始读取消息,进程%d完成第%d部分任务"%(os.getpid(),id))
ifnot q.empty():
fory in range(q.qsize()):
r= q.get()
ifr == "#!#":
print("消息队列已空")
break
else:
print(r)
else:
print("消息队列已空")
def main():
msg = input("请输入要传送的消息(单词用空格隔开):")
print(msg)
msg= list(msg.split(" "))
msg.append("#!#")
print(msg)
po= Pool(4)
qu= Manager().Queue(len(msg))
forid in range (10):
po.apply_async(writer,(qu,msg,id))
po.apply_async(reader,(qu,id))
po.close()
po.join()
if __name__ =="__main__":
main()
<<pool_queue.py>>
- 用python实现Linux系统编程——进程
- linux 系统编程——进程管理
- Linux系统编程——进程介绍
- Linux系统编程——进程管理
- Linux服务器编程——Linux系统编程之进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之孤儿进程
- Linux系统编程——特殊进程之守护进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之孤儿进程
- Linux系统编程——特殊进程之守护进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之孤儿进程
- Linux系统编程——特殊进程之守护进程
- Linux系统编程——特殊进程之僵尸进程
- Linux系统编程——特殊进程之孤儿进程
- 带你秒懂STIL文件
- Windows下通过Anaconda安装TensorFlow及Spyder编译器
- ios 设备权限
- 使用cocoapods时,import 找不到头文件
- GAE类软件使用中的错误以及排除方法
- 用python实现Linux系统编程——进程
- 蚁群算法 matlab程序详细解答-菜鸟也能看懂
- c++常见面试题30道
- 面试题16:反转链表
- oracle wallet使用与维护---oracle无密码登录
- POJ 1633 Gladiators 笔记
- ATPG之debug
- spring 事务,事务特性
- PHP中双引号和单引号的区别一览