Python课程设计 第 38 / 52 篇

进程并发-参考答案

写一个模拟100个用户抢10张火车票的程序,要求如下:

1 100个用户一定是并发查看票数余量,购票当然也是并发执行的
2 用户在购票时模拟网络延迟,可能查票的时候有票,但是购票的时候就没有了
3 进程之间的通信使用硬盘来完成
4 不能出现数据错误,比如多个用户买同一张票,购票成功却票数没减
5 不需要写用户的登录注册
import json
import time
import random
import os
from multiprocessing import Process, Lock

mutex = Lock()

# 互斥锁vs join的区别二:
# 互斥锁可以让一部分代码(修改共享数据的代码)串行,而join只能将代码整体串行

def check():
    time.sleep(random.randint(1, 3))
    with open('db.json', 'r', encoding='utf-8') as f:
        dic = json.load(f)
        print('%s 剩余票数:%s' % (os.getpid(), dic['count']))

def pay():
    with open('db.json', 'r', encoding='utf-8') as f:
        dic = json.load(f)
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1, 3))
        with open('db.json', 'w', encoding='utf-8') as f:
            json.dump(dic, f)
        print('%s 购票成功' % os.getpid())

def task(lock):
    check()
    lock.acquire()
    pay()
    lock.release()

if __name__ == '__main__':
    for i in range(100):
        p = Process(target=task, args=(mutex,))
        p.start()
  1. 基于网络通信写一个用户注册的程序,要求如下:
1 用户在客户端注册时,服务器会给用户的客户端发送一个随机验证码,用户使用它校验。
2 多个用户并发执行注册功能时服务端使用消息队列来处理用户请求
# 生产者消费者模型
import time
import random
import socket
from multiprocessing import Process, JoinableQueue

client = socket.socket()
client.connect(('127.0.0.1', 8099))

def consumer(name, q):
    """
    客户端是消费者,客户端发送验证码请求,并输入验证码
    :param name:
    :param q:
    :return:
    """
    while True:
        res = q.get()
        if res is None:
            break
        time.sleep(random.randint(1, 3))
        print('\033[46m消费者===》%s 使用了 %s\033[0m' % (name, res))
        q.task_done()

def producer(name, q, food):
    """
    服务端是生产者,服务端接收验证码请求,并发送验证码
    :param name:
    :param q:
    :param food:
    :return:
    """
    for i in range(5):
        time.sleep(random.randint(1, 2))
        res = '%s%s' % (food, i)
        q.put(res)
        print('\033[45m生产者者===》%s 生产了 %s\033[0m' % (name, res))

def recv_code():
    client.send('code'.encode('utf-8'))
    code = client.recv(1024).decode('utf-8')
    return code

if __name__ == '__main__':
    q = JoinableQueue()

    p1 = Process(target=producer, args=('1号服务器', q, recv_code()))
    p2 = Process(target=producer, args=('2号服务器', q, recv_code()))
    p3 = Process(target=producer, args=('3号服务器', q, recv_code()))
    c1 = Process(target=consumer, args=('悟空的客户端', q))
    c2 = Process(target=consumer, args=('八戒的客户端', q))
    c1.daemon = True  # 子进程变成守护进程
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
    # 确定生产者确实生产完毕
    p1.join()
    p1.join()
    p1.join()
    # 生产者生产完毕之后,拿到队列中肯定有还有数据,直到这个数据量变为0,q.join()这行代码才算是运行完毕
    q.join()
    # q.join()一旦结束就意味着队列确实为空,消费者已经确实把数据都取干净了。
    print('主进程结束')

    
# 验证码服务
import socket
import random

server = socket.socket()
server.bind(('127.0.0.1', 8099))
server.listen(5)

while True:
    conn, client = server.accept()
    print(client)
    while True:  # 通信循环
        try:
            msg = conn.recv(1024)
            print('客户端的消息: ', msg)

            code = ''
            for _ in range(4):
                code += str(random.randint(0, 9))
            conn.send(code.encode('utf-8'))
        except Exception:
            break
    conn.close()
server.close()