python基础day39 生产者消费者模型和线程相关

发布时间 2023-07-06 21:27:40作者: 追逐的小白

如何查看进程的id号

进程都有几个属性:进程名、进程id号(pid--->process id)

每个进程都有一个唯一的id号,通过这个id号就能找到这个进程

import os
import time
def task():
    print("task中的子进程号:", os.getpid())
    print("主进程中的进程号:", os.getppid())  # parent
    time.sleep(20)

from multiprocessing import Process

if __name__ == '__main__':
    p = Process(target=task, )
    p.start()
    # 如何查看p进程的进程号
    print("子进程的进程号:", p.pid)  # 217164
    # 如何查看主进程的进程号:
    print("主进程的进程号:", os.getpid()) # os.getgid()这一句代码写在哪个进程下,输出的就是这个进程的进程号
    time.sleep(10)

队列的使用(Queue)

常见的数据结构:链表、单链表、双链表、循环链表、栈、队列、树、二叉树、平衡二叉树、红黑树、b树、b+树、b-树、图等

队列:先进先出

怎样得到一个队列?

在python中有一个内置类:Queue

from multiprocessing import Queue

if __name__ == '__main__':
    q = Queue(3)  # 队列的大小默认很大
    # 1. 如何入队、
    """obj, block=True, timeout=None"""
    q.put('hellowrold1')
    q.put('helloworld2')
    q.put('helloworld3')
    # q.put('helloworld4', block=False)  # 如果你知道了block参数,当队列满的时候,放不进去的时候,直接报错
    # q.put('helloworld4', timeout=3)  # 如果你知道了timeout参数,当往队列中放入数据的时候,等待3秒,如果放不进去,直接报错
    # q.put_nowait('helloworld4')  # 往队列中放入数据的时候,放不进去直接报错, 指定了参数:block=False

    # 2. 出队
    # print(q.get())
    # print(q.get())
    print(q.get())
    """ block=True, timeout=None"""
    # print(q.get(block=False))
    # print(q.get(timeout=3))

    # q.get_nowait() #
    # print(q.qsize()) # 队列中剩余的数据量, 这个方法的结果有点不准确.
    # print(q.empty())
    # print(q.full())

解决进程之间的数据隔离问题

def task(q):
    a  = 1
    q.put("子进程写入的数据111")
    q.put(a)


from multiprocessing import Process,Queue

if __name__ == '__main__':
    q = Queue(3)
    p = Process(target=task,args=(q, ) )
    p.start()
    """
        我在子进程中放入一个数据,然后在主进程中取出这个数据,如果能去得到,就说明通信了,如果取不到就说明不通信
    """
    # 在主进程中取出子进程写进去的数据
    print(q.get())
    print(q.get())


'''现在队列中的数据在哪里存着? 在内存中,当数据量很大的时候,很占用我们机器的内存'''
# 以后我们可能会使用专业的消息队列:当前使用较多的消息队列有:RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等

生产者消费者模型

它不是只存在于python中,在其他语言中也是有的,甚至于它跟语言就没有关系

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题,该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

# 多生产者、少消费者情况
def producer(q, name, food):
    """让生产者生产10个包子"""
    for i in range(10):
        """生产的包子放在哪里? 队列里"""
        q.put("生产者:%s,生产了第%s个 %s" % (name, i, food))
        import time
        time.sleep(0.1)


def consumer(q):
    while True:
        res = q.get()

        # if q.empty():
        #     break
        if res is None:
            break
        print(res)


from multiprocessing import Process, Queue

if __name__ == '__main__':
    q = Queue(20)

    # 4个生产者
    p1 = Process(target=producer, args=(q, 'kevin', '包子'))
    p2 = Process(target=producer, args=(q, 'jason', '豆浆'))
    p3 = Process(target=producer, args=(q, 'tank', '面包'))
    p4 = Process(target=producer, args=(q, 'oscar', '豆汁'))
    p1.start()
    p2.start()
    p3.start()
    p4.start()

    # 两个消费者
    p5 = Process(target=consumer, args=(q,))
    p6 = Process(target=consumer, args=(q,))
    p5.start()
    p6.start()

    p1.join()
    p2.join()
    p3.join()
    p4.join()
    """放的None的数量超过消费者的数量就可以正常结束程序"""
    q.put(None)
    q.put(None)

队列可能会出现什么问题,如何解决的?
# 队列积压问题,队列里面的数据不能够被及时的消费掉造成的问题
# 把队列中的数据消费掉,以后我们会有专业的队列工具,是一个网站,手动的处理

线程理论

进程是一个任务的执行过程,在这个过程中实际做事的是线程,线程是开在进程里面的,需要先有进程,再有线程,一个进程中至少有一个线程,也可以有多个线程

进程是资源分配的基本单位,线程是CPU执行的最小单位

进程和线程都是由操作系统来调度的,协程它是由程序员来调度的

进程 >>> 线程 >>> 协程
资源消耗是最多的 >>> 线程的资源 >>> 协程的

我们学了进程和线程之后,以后到底是开多进程还是开多线程呢? ==》GIL锁相关

如何开启线程

def task():
    print("task执行了")  # task执行了


from multiprocessing import Process
from threading import Thread

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    
from multiprocessing import Process
from threading import Thread
import threading

if __name__ == '__main__':
    """
        target=None, name=None,
                 args=(), kwargs=None, *, daemon=None
                 
        name='ly_1': 修改线程名称
        
    """
    t = Thread(target=task, name='ly_1', args=('kevin', 'jason' ), kwargs={'age':18})
    # t.daemon = True
    # t.setDaemon(True)  # 守护线程:主线程结束,子线程跟着结束
    t.start()

    # print(t.name)  # Thread-1
    # print(123)

    #####几个方法
    # print(t.isAlive())
    # print(t.is_alive())
    # print(t.getName())
    # print(t.name)
    # t.setName('ly_2')
    # print(t.getName())
    print(threading.currentThread())  # <_MainThread(MainThread, started 110848)>

 

如何开启多线程

def task(i):
    print(i)


from threading import Thread
if __name__ == '__main__':
    tt = []
    for i in range(5):
        t = Thread(target=task, args=(i, ))
        t.start()
        tt.append(t)
    for j in tt:
        j.join()
        
    print("123")

进程和线程的比较

1. 进程的开销远远大于线程的开销

2. 进程之间的数据是隔离的,线程之间的数据是共享的,严格来说:同一个进程下的线程之间的数据是共享的

3. 想让不同进程之间的线程之间的数据共享------->还是让进程之间通信------->线程之间也通信了--->队列