网络编程——multiprocessing内置消息队列、IPC机制、生产者消费者模型、线程、GIL全局解释器锁


一、multiprocessing内置消息队列

消息队列是先进先出的,用于进行进程之间信息传递的。

from multiprocessing import Queue

q = Queue(3) # 设置队列长度

q.put(123) # 向队列添加元素
q.put(1234)
print("队列是否填满:",q.full()) # 判断队列是否填满
q.put(12345)
print("队列是否填满:",q.full())

print(q.get()) # 从队列取出元素
print("队列是否为空:",q.empty()) # 判断队列是否为空
print(q.get())
print(q.get_nowait()) # 从队列取一个元素,如果队列为空,则报错
print("队列是否为空:",q.empty())
print(q.get_nowait()) # 从队列取一个元素,如果队列为空,则报错

在这里插入图片描述

full()
empty()
get_nowait()
三个方法不能在并发的情况下精确使用。


二、IPC机制

IPC机制主要是用来处理以下几种情况的:

  1. 主进程与子进程之间的信息交互
  2. 子进程与子进程之间的信息交互
    其本质是不同内存空间的进程数据交互
from multiprocessing import Process, Queue

def dask(q, cont):
    print("子进程%d获取了一个数据信息:%s"%(cont, q.get()))

def se(q,cont , txt):
    q.put(txt)
    print("子进程%d存放了一个数据信息:%s"%(cont, txt))

if __name__ == '__main__':
    q = Queue(5)
    p1 = Process(target=dask, args=(q, 1))
    p2 = Process(target=se, args=(q, 2, "hello"))
    p2.start()
    p1.start()

在这里插入图片描述


三、生产者消费者模型

生产者指生成数据的部分
消费者指使用数据的部分

生产者消费者模型主要怕用于解决生产和使用之间的关系,生产过快或者消费过快都是不行的,此时便需要一个平衡,所以产生了生产者消费者模型。

在这里插入图片描述

from multiprocessing import Process, Queue
import time

def produce(q, num, commodity):
    for i in range(8):
        q.put(commodity + str(i))
        time.sleep(1)
        print("生产商%d生产了%s%d"%(num, commodity, i))

def consume(q, num):
    time.sleep(2)
    while True:
        if not q.empty():
            time.sleep(1)
            comm = q.get()
            print("消费者%d消费了%s"%(num, comm))
        else:
            print("没有商品了,消费者%d只剩下钱了"%num)
            return

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=produce, args=(q, 1, "苹果手机"))
    p2 = Process(target=produce, args=(q, 2, "苹果手机"))
    c1 = Process(target=consume, args=(q, 1))
    c2 = Process(target=consume, args=(q, 2))
    p1.start()
    p2.start()
    c1.start()
    c2.start()
    print("生产着消费者模型演示")

在这里插入图片描述


四、线程

1.线程是什么?

进程是资源单位,而线程是进程中的执行单位,一个进程中可以有多个线程,一个进程至少有一个线程。

  1. 线程的建立比进程消耗的资源少
  2. 进程仅仅是在内存中开辟一块空间(提供线程工作所需的资源)
  3. 线程真正被CPU执行,线程需要的资源跟所在进程的要

2.线程创建

Thread类中自带name属性,不可以修改name,一旦修改会报错,name值的含义为线程名-线程数

2.1 使用Thread创建

from threading import Thread

def desk(content):
    print("线程%d开启了"%content)
    print("线程%d结束了"%content)

t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t1.start()
t2.start()
t3.start()

在这里插入图片描述

2.2使用类来创建

from threading import Thread

class MyThread(Thread):
    def __init__(self, num):
        self.num = num
        super().__init__()

    def run(self):
        print("线程%d开启了" % self.num)
        print("线程%d结束了"% self.num)

t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()

3.线程数据

一个进程内的多个线程数据是共享的

4.线程同步

线程开启后默认都是异步处理的,此时使用join方法可以让投个线程变为同步运行。

from threading import Thread
import time

def desk(content):
    date = time.strftime("%Y %m %d %X")
    print(f"线程%d开启了,此时时间为:{date}"%content)
    time.sleep(content)
    date1 = time.strftime("%Y %m %d %X")
    print(f"线程%d结束了,此时时间为:{date1}"%content)

t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t3.join()
t2.start()
t1.start()

在这里插入图片描述

5.线程的属性与方法

5.1active_count

active_count()方法是获取当前开启的所有线程数量

from threading import Thread, active_count
import time

def desk(content):
    date = time.strftime("%Y %m %d %X")
    print(f"线程%d开启了,此时时间为:{date}"%content)
    time.sleep(3)
    date1 = time.strftime("%Y %m %d %X")
    print(f"线程%d结束了,此时时间为:{date1}"%content)

t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t2.start()
t1.start()
print("开启的线程数:",active_count())

在这里插入图片描述

5.2 获取线程名字

获取子线程名字时为子线程名字-子线程数
获取主线程名字时为MainThread

使用current_thread方法获取

from threading import Thread, active_count, current_thread
import time

def desk(content):
    date = time.strftime("%Y %m %d %X")
    print(f"线程%d开启了,此时时间为:{date}"%content)
    time.sleep(3)
    print("子线程名字:",current_thread().name)
    date1 = time.strftime("%Y %m %d %X")
    print(f"线程%d结束了,此时时间为:{date1}"%content)

t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t2.start()
t1.start()
print("开启的线程数:",active_count())
print("主线程名字", current_thread().name)

在这里插入图片描述

使用self.name获取

from threading import Thread

class MyThread(Thread):
    def __init__(self, num):
        self.num = num
        super().__init__()

    def run(self):
        print("线程%d开启了" % self.num)
        print("线程名字:", self.name)
        print("线程%d结束了"% self.num)

t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()

在这里插入图片描述

6.守护线程

守护线程在被守护线程结束后会直接结束。
守护线程通过设置daemon 来实现,设置守护线程需要在要设置为守护线程的启动之前完成。

from threading import Thread
import time

def desk(content):
    print(f"线程%d开启了"%content)
    time.sleep(3)
    print(f"线程%d结束了"%content)

t1 = Thread(target=desk, args=(1, ))
t1.daemon = True
t1.start()
print("主线程结束")

在这里插入图片描述


五、GIL全局解释器锁

官方文档
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

GIL只存在于CPython解释器中,不是python的特征
GIL是一把互斥锁用于阻止同一个进程下的多个线程同时执行
原因是因为CPython解释器中的垃圾回收机制不是线程安全的

反向验证GIL的存在 如果不存在会产生垃圾回收机制与正常线程之间数据错乱

GIL是加在CPython解释器上面的互斥锁
同一个进程下的多个线程要想执行必须先抢GIL锁 所以同一个进程下多个线程肯定不能同时运行 即无法利用多核优势

所有的解释型语言都无法做到同一个进程下多个线程利用多核优势

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值