用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-NN为从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

利用multiprocessingProcess类可以动态创建进程,但是当任务量比较大的时候,创建、删除、又创建进程会消耗很多时间,利用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之后使用;

 

使用进程池完成多进程任务,示例代码:

# -*-codingutf-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>>

原创粉丝点击