网络编程——GIL与普通互斥锁区别、死锁现象、信号量、event事件、进程池、线程池、协程


一、GIL与普通互斥锁区别

from threading import Thread

money = 100

def fask():
    global money
    money -= 1

for i in range(100):
    t = Thread(target=fask)
    t.start()
print(money) # 0

通过上面的操作验证了GIL全局解释器锁是存在的

from threading import Thread, Lock
import time

money = 100
mutex = Lock()

def fask():
    global money
    mutex.acquire()
    num = money
    time.sleep(0.1)
    money = num - 1
    mutex.release()

t_list = []
for i in range(100):
    t = Thread(target=fask)
    t.start()
    t_list.append(t)
for i in t_list:
    i.join()

print(money) # 0

二、死锁现象

当多个线程同时需要某一个锁的资源时,无法获取锁的资源会等待获取,多个线程都互相等待对方锁的资源,就会产生死锁现象。

def play(num):
    mutexA.acquire()
    print("子进程%d获取A锁"%num)
    time.sleep(3)
    mutexB.acquire()
    print("子进程%d获取B锁"%num)
    mutexB.release()
    print("子进程%d释放B锁"%num)
    mutexA.release()
    print("子进程%d释放A锁" % num)

def play1(num):
    mutexB.acquire()
    print("子进程%d获取B锁"%num)
    time.sleep(3)
    mutexA.acquire()
    print("子进程%d获取A锁" % num)
    mutexA.release()
    print("子进程%d释放A锁"%num)
    mutexB.release()
    print("子进程%d释放B锁"%num)

t = Thread(target=play, args=(1, ))
t1 = Thread(target=play1, args=(2, ))
t.start()
t1.start()

在这里插入图片描述


三、信号量

信号量在不同的知识体系中 展示出来的功能是不一样的
在互斥锁中展现为多个可以被多个资源获取的互斥锁

同一时刻只有三个线程可以使用fask方法创建并开启进程

from threading import Thread, Semaphore
import time
import random

sp = Semaphore(3)

def fask(num):
    sp.acquire()
    print("%d号子弹飞出"%num)
    time.sleep(random.randint(1, 2))
    sp.release()
    print("%d子弹命中"%num)

for i in range(20):
    t = Thread(target=fask, args=(i, ))
    t.start()

在这里插入图片描述


四、event事件

一般情况下子线程的运作是与主线程有关的,但使用了event后可以让子线程决定子线程的运行状况

from threading import Thread, Event
import time

eventO = Event()

def wait_time():
    print("三秒后即将开始抢玻璃")
    time.sleep(3)
    print("三秒到开始抢玻璃")
    eventO.set()

def get_glass(num):
    print("%d号选手正在参与抢玻璃!"%num)
    eventO.wait()
    print("%d号选手抢到了玻璃!"%num)

t = Thread(target=wait_time)
t.start()

for i in range(1, 31):
    t1 = Thread(target=get_glass, args=(i, ))
    t1.start()

在这里插入图片描述

五、进程池

计算机硬件是有物理极限的 我们不可能无限制的创建进程
进程池保证计算机硬件安全的情况下提升程序的运行效率,提前创建好固定数量的进程 后续反复使用这些进程,如果任务超出了池子里面的最大进程数 则原地等待
进程池其实降低了程序的运行效率 但是保证了硬件的安全

from concurrent.futures import ProcessPoolExecutor
import time

def make_pool(num):
    print("%d号子进程正在被处理"%num)
    start_time = time.strftime("%Y %m %d %X")
    print(f"开始时间{start_time}")
    time.sleep(1)

def func(*args, **kwargs):
    args[0].result()

if __name__ == '__main__':
    pool = ProcessPoolExecutor(2)
    for i in range(1, 11):
        pool.submit(make_pool, i).add_done_callback(func)

在这里插入图片描述


六、线程池

计算机硬件是有物理极限的 我们不可能无限制的创建线程
线程池保证计算机硬件安全的情况下提升程序的运行效率,提前创建好固定数量的线程 后续反复使用这些线程,如果任务超出了池子里面的最大线程数 则原地等待
线程池其实降低了程序的运行效率 但是保证了硬件的安全

from concurrent.futures import ThreadPoolExecutor
import time

def make_pool(num):
    print("%d号子线程正在被处理"%num)
    start_time = time.strftime("%Y %m %d %X")
    print(f"开始时间{start_time}")
    time.sleep(1)

def func(*args, **kwargs):
    args[0].result()


pool = ThreadPoolExecutor(2)
for i in range(1, 11):
    pool.submit(make_pool, i).add_done_callback(func)

在这里插入图片描述


七、协程

协程的主要目的是在单线程下完成并发,其本质是在于不断切换状态,在多个需要资源的代码之间来回服务。协程就是自己通过代码来检测程序的IO操作并自己处理 让CPU感觉不到IO的存在从而最大幅度的占用CPU。

from gevent import monkey;monkey.patch_all()  # 固定编写 用于检测所有的IO操作
from gevent import spawn
import time

def play(name):
    print('%s play 1' % name)
    time.sleep(5)
    print('%s play 2' % name)

def eat(name):
    print('%s eat 1' % name)
    time.sleep(3)
    print('%s eat 2' % name)

start_time = time.time()
g1 = spawn(play, 'jason')
g2 = spawn(eat, 'jason')
g1.join()  # 等待检测任务执行完毕
g2.join()  # 等待检测任务执行完毕
print('总耗时:', time.time() - start_time)

协程完成服务器与客户端的信息交互

服务器

from gevent import monkey;monkey.patch_all()
from gevent import spawn
import socket

def create_server():
    server = socket.socket()
    server.bind(("127.0.0.1", 8080))
    server.listen(5)
    while True:
        sock, addr = server.accept()
        spawn(communication, sock, addr)

def communication(sock, addr):
    while True:
        data = sock.recv(1024)
        print(f"{addr}客户端:{data.decode('utf8')}")
        sock.send("服务器收到消息".encode("utf8"))

spawn(create_server).join()

客户端

import socket

client = socket.socket()
client.connect(("127.0.0.1", 8080))
while True:
    client.send("协程信息测试".encode("utf8"))
    data = client.recv(1024)
    print(f"服务器:{data.decode('utf8')}")


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值