• Python学习第49天(多进程调用)


      昨天的生产者消费者模型其实自己没有怎么认真听,因为前几天上班太忙消耗太大,导致昨晚太困,多次电脑砸脸,所以今天再详细说一下生产者消费者模型。

      主要是利用queue来实现一个生产者和消费者之前的联通,其实在之前曾经利用过列表来实现,但是明显那种方式非常的不合适,生产者和消费者之间的联系太强了,基本都是生产完开始吃,亦或者边生产边吃,没有体现出生产者和消费者之间的随机联系。

      下面这版本应该是最初的,通过判断队列q是否为空来时消费者和生产者之间取得联系:

    import random,queue,time
    import threading
    
    q = queue.Queue()
    def product(name):
        count = 0
        while count < 10 :
            print('%s is making.'%name)
            time.sleep(random.randrange(3))
            q.put(str(count) + 'baozi')
            print('%s had made No.%s baozi'%(name,count))
            count += 1
    
    def consumer(name):
        count = 0
        # print(q.empty())
        while count < 10 :
            if q.empty():
                data = q.get()
                print('33[32; %s is eating %s 33[0m'%(name,data))
                time.sleep(random.randrange(4))
            else:
                print('no baozi anymore')
                print('waiting')
            count += 1
    
    if __name__ == '__main__':
        t1 = threading.Thread(target = product ,args = ('zhaolei',))
        t2 = threading.Thread(target = consumer , args = ('zjl',))
        t3 = threading.Thread(target = consumer , args = ('mayday',))
        t4 = threading.Thread(target = consumer , args = ('golo',))
        t1.start()
        t2.start()
        t3.start()
        t4.start()

      上面这个是具有了一定的结耦,但是还不是很明显,我们昨天说过q.join()和 q.task_done()

      当完成一个队列加入的时候 q.task_done()就会释放信号,被q.join()接收到,如果没有接收到信息,该线程会在q.join()这里进行等待,知道收到为止,上面我们是通过q.empty()实现的,下面解锁一下新的情况吧

    import random,queue,time
    import threading
    
    q = queue.Queue()
    def product(name):
        count = 0
        while count < 10 :
            print('%s is making.'%name)
            time.sleep(random.randrange(3))
            q.put(str(count) + 'baozi')
            print('%s had made No.%s baozi'%(name,count))
            q.task_done()
            count += 1
    
    def consumer(name):
        count = 0
        while count < 10:
            print('%s is waiting'%name)
            q.join()
            data = q.get()
            print('33[32; %s is eating %s 33[0m'%(name,data))
            time.sleep(random.randrange(2))
            # print(q.empty())
    
    
    if __name__ == '__main__':
        t1 = threading.Thread(target = product ,args = ('zhaolei',))
        t2 = threading.Thread(target = consumer , args = ('zjl',))
        t3 = threading.Thread(target = consumer , args = ('mayday',))
        t4 = threading.Thread(target = consumer , args = ('golo',))
        t1.start()
        t2.start()
        t3.start()
        t4.start()

      同时这样的q.join()和 q.task_done()之间的信息交互,我们也可以反过来用,正好就是顾客吃完一个,老板才会开始继续做

    以上就是多线程的部分了,下面进入多线程部分

    Python为了弥补不能使用多核电脑福利的遗憾,引入了设置进程的概念,这样就是多个GIL,实现了的资源利用的最大化

      专业的说法:由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。

      multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

      先看一下多进程的调用方式:

    from multiprocessing import Process
    import time
    def f(name):
        time.sleep(1)
        print('hello', name,time.ctime())
    
    if __name__ == '__main__':
        p_list=[]
        for i in range(3):
            p = Process(target=f, args=('alvin',))
            p_list.append(p)
            p.start()
        for i in p_list:
            p.join()
        print('end')

      方式2:

    from multiprocessing import Process
    import time
    
    class MyProcess(Process):
        def __init__(self):
            super(MyProcess, self).__init__()
            #self.name = name
    
        def run(self):
            time.sleep(1)
            print ('hello', self.name,time.ctime())
    
    
    if __name__ == '__main__':
        p_list=[]
        for i in range(3):
            p = MyProcess()
            p.start()
            p_list.append(p)
    
        for p in p_list:
            p.join()
    
        print('end')

      调用的方式来看,基本是和多线程很像

    然后是这个类的一些实际属性吧:

      构造方法:

      Process([group [, target [, name [, args [, kwargs]]]]])

        group: 线程组,目前还没有实现,库引用中提示必须是None; 

        target: 要执行的方法; 

        name: 进程名; 

        args/kwargs: 要传入方法的参数。

      实例方法:

        is_alive():返回进程是否在运行。

        join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。

        start():进程准备就绪,等待CPU调度

        run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。

        terminate():不管任务是否完成,立即停止工作进程

      属性:

        daemon:和线程的setDeamon功能一样

        name:进程名字。

        pid:进程号。

        getpid:获得进程号。

        getppid:获得父类进程的进程号。

    今天的内容就是这些,我有点想不起来socket部分的知识了,所以明天更新了多进程周后,我打算开始转回去进行知识的复习,正好下周要去查办一个非常重要的人。

    今晚要睡得正常,明天去理个发。

  • 相关阅读:
    梦断代码阅读笔记03
    第十二周进度条
    找“水王”
    梦断代码阅读笔记02
    梦断代码阅读笔记01
    团队开发第二阶段个人博客(2)
    团队开发第二阶段个人博客(1)
    个人总结
    第16周学习进度条
    个人进度条第15周
  • 原文地址:https://www.cnblogs.com/xiaoyaotx/p/12683172.html
Copyright © 2020-2023  润新知