zoukankan      html  css  js  c++  java
  • python进阶03

    进程线程不管哪门语言都是一块可以被重视的方向,下面一起学习学习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.线程

       1)threading模块

        通过这个模块将thread封装能更好操作

        2.1.1 注意:  

          一个进程所有线程共享全局变量,但这可能会造成线程安全

      2)锁

        当多个线程同时修改同一个共享数据时,需要进行同步控制

        创建方式

    #创建锁
    mutex = threading.Lock()
    #锁定
    mutex.acquire([blocking])
    #释放
    mutex.release()

        例子

    from threading import Thread, Lock
    import time
    
    g_num = 0
    
    def test1():
        global g_num
        for i in range(1000000):
            #True表示堵塞 即如果这个锁在上锁之前已经被上锁了,那么这个线程会在这里一直等待到解锁为止 
            #False表示非堵塞,即不管本次调用能够成功上锁,都不会卡在这,而是继续执行下面的代码
            mutexFlag = mutex.acquire(True) 
            if mutexFlag:
                g_num += 1
                mutex.release()
    
        print("---test1---g_num=%d"%g_num)
    
    def test2():
        global g_num
        for i in range(1000000):
            mutexFlag = mutex.acquire(True) #True表示堵塞
            if mutexFlag:
                g_num += 1
                mutex.release()
    
        print("---test2---g_num=%d"%g_num)
    
    #创建一个互斥锁
    #这个所默认是未上锁的状态
    mutex = Lock()
    
    p1 = Thread(target=test1)
    p1.start()
    
    
    p2 = Thread(target=test2)
    p2.start()
    
    print("---g_num=%d---"%g_num)
    View Code

        锁好是好,但也可能造成死锁情况

        局部变量是各个线程自己的非共享

      3)TheadLocal

        ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题

        实实在在的解决了开发过程中的问题

        用法:local_school = threading.local()

    import threading
    
    # 创建全局ThreadLocal对象:
    local_school = threading.local()
    
    def process_student():
        # 获取当前线程关联的student:
        std = local_school.student
        print('Hello, %s (in %s)' % (std, threading.current_thread().name))
    
    def process_thread(name):
        # 绑定ThreadLocal的student:
        local_school.student = name
        process_student()
    
    t1 = threading.Thread(target= process_thread, args=('dongGe',), name='Thread-A')
    t2 = threading.Thread(target= process_thread, args=('老王',), name='Thread-B')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    View Code

        

  • 相关阅读:
    json数组去重
    java socket API
    java网络编程精解demo1---读取用户控制台的输入的数据并显示
    【CodeForces 489A】SwapSort
    【CSU 1556】Pseudoprime numbers
    【CodeForces 472A】Design Tutorial: Learn from Math
    【CodeForces 605A】BUPT 2015 newbie practice #2 div2-E
    【UVALive 3905】BUPT 2015 newbie practice #2 div2-D-3905
    【HDU 4925】BUPT 2015 newbie practice #2 div2-C-HDU 4925 Apple Tree
    【UVA 401】BUPT 2015 newbie practice #2 div2-B-Palindromes
  • 原文地址:https://www.cnblogs.com/xiaoping1993/p/9709973.html
Copyright © 2011-2022 走看看