进程理论和实操

创建进程的多种方式

  • 双击桌面程序图标
  • 代码创建进程,需要掌握如下两种
方式1:
  def task(name):
    print(f'子进程{name}开始运行')
    time.sleep(2)
    print(f'子进程{name}运行结束')

if __name__ == '__main__':
    p = Process(target=task,args=('jason',))
    p.start()
    print('主进程')

方式2:
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        # 当我们把name写在super上面时,name会被super里面继承的Process的父类BaseProcess里面的name覆盖,所以可以写在下面
        self.name= name
    def run(self):
        print(f'子进程{self.name}开始运行')
        time.sleep(2)
        print(f'子进程{self.name}结束运行')

if __name__ == '__main__':
    p = MyProcess('jason')
    p.start()
    print('主进程')

创建进程的代码在不同的操作系统中,底层原理有区别。

  1. 在windows中,创建进程类似于导入模块

    if __name__== '__main__':启动脚本,这样就不会报错
    
  2. 在Mac、linux中,创建进程类似于直接拷贝

    不需要启动脚本,但是为了兼容性,也可以使用

join方法

join方法的定义:主进程等待子进程运行结束之后在运行

代码演示:

import time
from multiprocessing import Process

def task(name,n):
    print(f'子进程{name}开始运行')
    time.sleep(n)
    print(f'子进程{name}结束运行')

if __name__ == '__main__':
    p = Process(target=task,args=('jason',1,))
    p1 = Process(target=task, args=('jason', 2,))
    p2 = Process(target=task, args=('jason', 3,))
    start_time = time.time()
    p.start()
    p1.start()
    p2.start()
    p.join()
    p1.join()
    p2.join()
    print('主进程程')
    end_time = time.time()-start_time
    print('总耗时为:%s' %end_time)
    
 "多任务下,一定要看好对应任务join的执行位置以及等待的目标"

进程间数据默认隔离

多个进程数据彼此之间默认是相互隔离的,但是如果真的想交互,可以借助于管道或者队列

from multiprocessing import Process

money = 100
def task():
    global money
    money=200

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print(f'父进程打印的{money}')

进程间通信(IPC机制)

# 预备知识:什么是队列:先进先出
from multiprocessing import Queue
# 创建一个队列对象
q = Queue(5)
q.put(100)
q.put(200)
print(q.full())    # 判断队列是否已经满了
print(q.get_nowait())  # 队列中如果没有数据可取,那么直接报错
q.get()
print(q.empty())  # 判断队列是否已经空了

q.full()
q.get_nowait()
q.empty()

上诉三种方法在多进程下不能准备使用(失效)

IPC机制

IPC机制可分为两种:1.主进程与子进程通信、2.子进程与子进程通信

from multiprocessing import Queue,Process
def procedure(q):
    q.put('生产者向队列中生产了数据')
def consumer(q):
    print('消费者从队列中获取了数据: %s' % q.get())

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=procedure,args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

生产者消费者模型

生产者即产生数据,消费者即处理数据

之间学习的爬取红牛分公司的生产者就是获取网页数据的代码(函数)即,消费者就是从网页数据中筛选出符合条件的数据(函数)即筛选

完整的生产者消费者模型至少有三个部分:

  • 生产者
  • 消费队列/数据库
  • 消费者

进程相关方法

1.查看进程号(有如下两个模块可以用)
  from multiprocessing import current_process,Process
  import os
  current_process().pid  	# 获取当前进程
  os.getpid()  						# 获取当前进程的id
  os.getppid()  					# 获取当前进程的父进程id

2.销毁子进程
	 p.terminate()
  
3.判断进程是否存活
   p.is_alive()

守护进程

守护进程即:将子进程设置为守护进程,那么主进程代码结束,子进程立刻结束

from multiprocessing import Process
import time
def task():
    print('子进程开始运行')
    time.sleep(2)
    print('子进程结束运行')

if __name__ == '__main__':
    p = Process(target=task)
    p.daemon=True  # 必须在start前面
    p.start()
    time.sleep(1)
    print('主进程')

僵尸进程与孤儿进程

  • 僵尸进程:进程已经运行结束,但是相关的资源并没有完全清空,需要父进程参与回收。每个进程结束后,都会进入短暂的僵尸进程状态
  • 孤儿进程:父进程意外死亡,子进程正常运行,该子进程就称之为孤儿进程;孤儿进程也不是没有人管,操作系统会自动分配福利院接受

互斥锁

模拟抢票

import json
from multiprocessing import Process
import time
import random

def search(name):
    with open('data.json','r',encoding='utf8') as f:
        data = json.load(f)
        ticket = data.get('ticket')
    print(f'{name}查看了剩余的票数,还剩{ticket}张')
def buy(name):
    with open('data.json','r',encoding='utf8') as f:
        data = json.load(f)
    # 模拟网络延迟
    time.sleep(random.randint(1,2))
    # 判断是否有票
    if data.get('ticket')>0:
        print(f'{name}买了一张票,还剩{data.get("ticket")}张票')
        data['ticket'] -=1
        with open('data.json', 'w', encoding='utf8') as f:
            json.dump(data,f)
    else:
        print('对不起,票以售空!')

def run(name):
    search(name)
    buy(name)


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run,args=(f'用户{i}',))
        p.start()

作业

将tcp服务端制作成并发效果
import socket
from multiprocessing import Process
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
def connect(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())

if __name__ == '__main__':
    while True:
        sock, addr = server.accept()
        p = Process(target=connect,args=(sock,))
        p.start()
posted @ 2022-08-09 16:58  荀飞  阅读(50)  评论(0)    收藏  举报