码迷,mamicode.com
首页 > 编程语言 > 详细

python进阶03

时间:2018-09-26 22:10:34      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:元组   读数   单元   平台   运行机制   属性   修改   结束   维护   

进程线程不管哪门语言都是一块可以被重视的方向,下面一起学习学习python中的进程,线程

1.进程线程区别

  通俗解释:一个程序QQ的运行就是一个进程运行;QQ中打开多个页面互不影响可以同时操作的每个页面的运作就是线程

  专业解释:进程-担当系统分配资源(CPU时间,内存)基本单元;线程-程序执行的最小单元

2.进程

  1)fork()

    2.1.1:介绍

      linux可以多进程操作,所以它能实现登录多个QQ;os模块封装了fork()方法能创建一个进程

      操作系统会创建一个新的进程,复制父进程所有信息到子进程中;

      fork()函数一定会得到一个返回值,子进程中为0,父进程中就是子进程的id号;

      父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID;

      getpid():放回当前进程标识;getppid():返回父进程标识

    2.1.2:用法  

技术分享图片
import os

rpid = os.fork()
if rpid<0:
    print("fork调用失败。")
elif rpid == 0:
    print("我是子进程(%s),我的父进程是(%s)"%(os.getpid(),os.getppid()))
    x+=1
else:
    print("我是父进程(%s),我的子进程是(%s)"%(os.getpid(),rpid))

print("父子进程都可以执行这里的代码")


运行结果:
我是父进程(19360),我的子进程是(19361)
父子进程都可以执行这里的代码
我是子进程(19361),我的父进程是(19360)
父子进程都可以执行这里的代码
View Code

  2)注意

    多进程中所有数据(包括全局变量)都各有一份,互不影响

  3)multiprocessing 

    2.3.1:介绍

      跨平台的非linux支持的多进程模块,提供了一个Process类代表一个进程对象

    2.3.2:Process-进程创建

      Process([group [, target [, name [, args [, kwargs]]]]])
        target:表示这个进程实例所调用对象;
        args:表示调用对象的位置参数元组;
        kwargs:表示调用对象的关键字参数字典;
        name:为当前进程实例的别名;
        group:大多数情况下用不到;
       Process类常用方法:
        is_alive():判断进程实例是否还在执行;
        join([timeout]):是否等待进程实例执行结束,或等待多少秒;
        start():启动进程实例(创建子进程);
        run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
        terminate():不管任务是否完成,立即终止;
      Process类常用属性:
        name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
        pid:当前进程实例的PID值;

    2.3.3 例子

技术分享图片
from multiprocessing import Process
import os
from time import sleep

# 子进程要执行的代码
def run_proc(name, age, **kwargs):
    for i in range(10):
        print(子进程运行中,name= %s,age=%d ,pid=%d... % (name, age,os.getpid()))
        print(kwargs)
        sleep(0.5)

if __name__==__main__:
    print(父进程 %d. % os.getpid())
    p = Process(target=run_proc, args=(test,18), kwargs={"m":20})
    print(子进程将要执行)
    p.start()
    sleep(1)
    p.terminate()
    p.join()
    print(子进程已结束)
View Code
技术分享图片
运行结果:
父进程 21378.
子进程将要执行
子进程运行中,name= test,age=18 ,pid=21379...
{m: 20}
子进程运行中,name= test,age=18 ,pid=21379...
{m: 20}
子进程已结束
View Code

    2.3.4 Process子类-进程创建

      创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类

      例子:

技术分享图片
from multiprocessing import Process
import time
import os

#继承Process类
class Process_Class(Process):
    #因为Process类本身也有__init__方法,这个子类相当于重写了这个方法,
    #但这样就会带来一个问题,我们并没有完全的初始化一个Process类,所以就不能使用从这个类继承的一些方法和属性,
    #最好的方法就是将继承类本身传递给Process.__init__方法,完成这些初始化操作
    def __init__(self,interval):
        Process.__init__(self)
        self.interval = interval

    #重写了Process类的run()方法
    def run(self):
        print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
        t_start = time.time()
        time.sleep(self.interval)
        t_stop = time.time()
        print("(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
    t_start = time.time()
    print("当前程序进程(%s)"%os.getpid())        
    p1 = Process_Class(2)
    #对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,所以这里会执行p1.run()
    p1.start()
    p1.join()
    t_stop = time.time()
    print("(%s)执行结束,耗时%0.2f"%(os.getpid(),t_stop-t_start))
View Code

  4)进程池

    当子进程不多,直接用multprocessing中的Process动态生成多个进程,但如果是很多,手动创建工作量很大,此时就可以用multprocessing模块提供的pool方法了

    运行机制:初始化进程池时可以指定最大进程数,当有新请求会先看进程池运行进程是否达到最大进程数,没有就创建一个进程放入进程池来维护同时运行子进程

multiprocessing.Pool常用函数解析:
    apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
    apply(func[, args[, kwds]]):使用阻塞方式调用func
    close():关闭Pool,使其不再接受新的任务;
    terminate():不管任务是否完成,立即终止;
    join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;

    例子:

技术分享图片
from multiprocessing import Pool
import os,time,random

def worker(msg):
    t_start = time.time()
    print("%s开始执行,进程号为%d"%(msg,os.getpid()))
    #random.random()随机生成0~1之间的浮点数
    time.sleep(random.random()*2) 
    t_stop = time.time()
    print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))

po=Pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
    #Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
    #每次循环将会用空闲出来的子进程去调用目标
    po.apply_async(worker,(i,))

print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")


运行结果:
----start----
0开始执行,进程号为21466
1开始执行,进程号为21468
2开始执行,进程号为21467
0 执行完毕,耗时1.01
3开始执行,进程号为21466
2 执行完毕,耗时1.24
4开始执行,进程号为21467
3 执行完毕,耗时0.56
5开始执行,进程号为21466
1 执行完毕,耗时1.68
6开始执行,进程号为21468
4 执行完毕,耗时0.67
7开始执行,进程号为21467
5 执行完毕,耗时0.83
8开始执行,进程号为21466
6 执行完毕,耗时0.75
9开始执行,进程号为21468
7 执行完毕,耗时1.03
8 执行完毕,耗时1.05
9 执行完毕,耗时1.69
-----end-----
View Code

  5)进程间的通信-Queue

    Process之间有时也需要通信,操作系统提供了很多机制来实现进程间通信

    2.5.1 Queue方法介绍  

初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);

Queue.qsize():返回当前队列包含的消息数量;

Queue.empty():如果队列为空,返回True,反之False ;

Queue.full():如果队列满了,返回True,反之False;

Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;

     例子

技术分享图片
from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    for value in [A, B, C]:
        print Put %s to queue... % value
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    while True:
        if not q.empty():
            value = q.get(True)
            print Get %s from queue. % value
            time.sleep(random.random())
        else:
            break

if __name__==__main__:
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()    
    # 等待pw结束:
    pw.join()
    # 启动子进程pr,读取:
    pr.start()
    pr.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    print ‘‘
    print 所有数据都写入并且读完
View Code

    2.5.2 进程池中的Queue

    如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue()

     例子

技术分享图片
#coding=utf-8

#修改import中的Queue为Manager
from multiprocessing import Manager,Pool
import os,time,random

def reader(q):
    print("reader启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
    for i in range(q.qsize()):
        print("reader从Queue获取到消息:%s"%q.get(True))

def writer(q):
    print("writer启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
    for i in "dongGe":
        q.put(i)

if __name__=="__main__":
    print("(%s) start"%os.getpid())
    q=Manager().Queue() #使用Manager中的Queue来初始化
    po=Pool()
    #使用阻塞模式创建进程,这样就不需要在reader中使用死循环了,可以让writer完全执行完成后,再用reader去读取
    po.apply(writer,(q,))
    po.apply(reader,(q,))
    po.close()
    po.join()
    print("(%s) End"%os.getpid())
View Code

 

  

2.线程

 

python进阶03

标签:元组   读数   单元   平台   运行机制   属性   修改   结束   维护   

原文地址:https://www.cnblogs.com/xiaoping1993/p/9709973.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!