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('\033[32; %s is eating %s \033[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('\033[32; %s is eating %s \033[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部分的知识了,所以明天更新了多进程周后,我打算开始转回去进行知识的复习,正好下周要去查办一个非常重要的人。

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

posted @ 2020-04-11 23:49  崆峒山肖大侠  阅读(220)  评论(0编辑  收藏  举报