并发编程(进程)——创建进程的两种方式,进程间数据相互隔离,进程调度,僵尸进程与孤儿进程,进程对象及其他方法,守护进程,互斥锁,队列介绍,IPC机制(进程间通信)

一、创建进程的两种方式

 

#第一种
from multiprocessing import Process
import time


def task(n):
    print('我是子进程')
    time.sleep(n)
    print('子进程结束')


if __name__ == '__main__':
    # args=(), kwargs={}
    # t=Process(task,args=(1,))
    t = Process(target=task, kwargs={'n': 1})
    t.start()  # 通知操作系统,开启进程,执行task函数
    print('')

#第二种:
from multiprocessing import Process
import time

class Task(Process):
    def __init__(self, n):
        super().__init__()
        self.n = n

    def run(self):
        print('我是子进程')
        time.sleep(self.n)
        print('子进程结束')


if __name__ == '__main__':
    t = Task(1)
    # t.run(1)  # 不是调用t.run(),而是调用t.start()
    t.start()
    print('')

二、进程间数据相互隔离

#进程之间数据隔离
from multiprocessing import Process
import time

age = 18


def task(n):
    global age  # 局部修改全局
    age = 99
    print('我是子进程')
    time.sleep(n)
    print('子进程结束')
    print(age)


if __name__ == '__main__':
    t = Process(target=task, kwargs={'n': 1})
    t.start()
    t.join()  # 等待t子进程执行完成
    print('')
    print(age) # 数据没有变,主进程中打印age和子进程的age没有半毛钱关系,数据是隔离的

三、进程调度

 1 先来先服务(对长作业有利,对短作业无益)
2 短作业优先(对短作业有利,对长作业无益)
3 时间片轮转
4 多级反馈队列

四、僵尸进程与孤儿进程

1 僵尸进程:进程结束了,资源还没来得及回收
2 孤儿进程:主进程挂了,子进程还没结束,它就会被专门的进程接管

五、进程对象及其他方法

1 windows:tasklist |findstr 进程id号
2 mac,Linux:ps aux | grep 进程id号
3 进程对象:t=Process(target=task, )或者是在进程内部:current_process()
4 t.pid或者current_process().pid 获取进程id号
5 os.getpid() 同上,获取进程id号
6 os.getppid() 获取父进程id号,子进程中获取父进程id,等于父进程的id号
7 t.is_alive()或者current_process().is_alive() 查看进程是否存活
8 t.terminate() 关闭进程,在主进程关闭
from multiprocessing import Process,current_process
import time
import os

# 每个进程都会有自己的id号pid

def task():
    print('子进程')

    # 当前进程的id号
    print(current_process().pid)
    print(os.getpid()) # 跟上面打印出来是一模一样的
    # 取出该进程父id号
    print('-----',os.getppid())
    # current_process()当前进程对象

    print(current_process().is_alive())
    time.sleep(2)

    print('子进程结束')


if __name__ == '__main__':
    t = Process(target=task, )
    t.start()
    # t1 = Process(target=task, )
    # t1.start()
    # t.is_alive()  # t这个进程是否存活
    # print('主进程打印的结果',t.is_alive())
    print(t.pid)
    time.sleep(0.5)
    # t.terminate()  # 把t进程关闭
    # time.sleep(0.1)
    print('主进程打印的结果', t.is_alive())

六、守护进程

from multiprocessing import Process, current_process
import time
import os


def task():
    # print(os.getpid())
    print('子进程')
    time.sleep(200)
    print('子进程结束')


if __name__ == '__main__':
    t = Process(target=task, )
    # 守护进程:主进程一旦结束,子进程也结束
    # t.daemon=True  # 一定要加在启动之前
    t.start()

    time.sleep(1)
    print('主进程结束')
    print(os.getppid())
    time.sleep(100)


# 问题1 :主进程的父进程是谁? 
答案:就是pycharm

# 问题2 :主进程开了很多子进程,每个都需要设置守护吗?
答案:看你的需求,你想让某个进程是守护:t.daemon=True

七、互斥锁

同时只有一个人能拿到,必须释放,其他人才能再次获取到
from multiprocessing import Process, Lock
import json
import time
import random


def search():
    # 查票的函数
    # 打开文件,读出ticket_count
    with open('ticket', 'r', encoding='utf-8') as f:
        dic = json.load(f)
        print('余票还有:', dic.get('ticket_count'))


def buy():
    with open('ticket', 'r', encoding='utf-8') as f:
        dic = json.load(f)

    time.sleep(random.randint(1, 3))  # 模拟一下网络延迟
    if dic.get('ticket_count') > 0:
        # 能够买票
        dic['ticket_count'] -= 1
        # 保存到文件中去
        with open('ticket', 'w', encoding='utf-8') as f:
            json.dump(dic, f)
            print('买票成功')
    else:
        # 买票失败
        print('买票失败')


# 写一个函数,先查票,再买票

def task(mutex):
    search()
    # 买票过程要加锁
    # 买前加锁
    # mutex.acquire()
    # buy()  # 10个进程变成了串行执行
    # # 买后释放锁
    # mutex.release()
    with mutex:
        buy()


if __name__ == '__main__':
    # 锁的创建,在哪?主进程创建锁
    mutex = Lock()  # 创建一把锁
    # 模拟十个人买票(开10个进程)
    for i in range(10):
        t = Process(target=task, args=(mutex,))
        t.start()

# 面向对象高级:魔法方法(__开头的),__enter__和__exit__,上下文管理器
# 自己写一个类,实现类似于打开文件 with open 的功能
# with MyClass('文件名','方式','编码')  as f:
#     f.read()


#在这写代码,f就关闭了

接上面问题  补充:

魔法方法之:__inter__  __exit__

class MyClass():
    def __init__(self,file_name,mode,encoding):
        self.file_name=file_name
        self.mode=mode
        self.encoding=encoding

    def __enter__(self):
        print('只要有with,就会执行我')
        self.file=open(self.file_name,self.mode,encoding=self.encoding)

        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 只要顶格写代码,就会执行我
        print('只要顶格写代码,就会执行我')
        self.file.close()


with MyClass('ticket','r','utf-8') as f:
    print(f.read())
    print('xxss')
    print("sdfadasf")


# a=MyClass('ticket','r','utf-8')#这样做不会打印__enter__里的内容

八、队列介绍

from multiprocessing import Queue

# 实例化得到要给对象

q=Queue(5)  # 默认很大,可以放很多,写了个5,只能放5个

# 往管道中放值
q.put(1)
q.put('lqz')
q.put(18)
q.put(19)
# q.put(20)
# q.put(21)
# q.put_nowait(100)

# 从管道中取值
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get(timeout=100))  # 等0.1s还没有值,就结束
# print(q.get_nowait())        # 不等了,有就是有,没有就没有

print(q.empty())  # 看一下队列是不是空的
print(q.full())   # 看一下队列是不是满的
q=Queue(队列大小)
# 放值
q.put(asdf)
q.put_nowait(asdf) # 队列满了,放不进去就不放了,报错

# 取值
q.get() # 从队列头部取出一个值
q.get_nowait() # 从队列头部取值,没有就抛错


# 队列是否为空,是否满
print(q.empty()) # 看一下队列是不是空的
print(q.full()) # 看一下队列是不是满的

九、IPC机制(进程间通信)

Inter-Process Communication,进程间通信
from multiprocessing import Process, current_process, Queue
import time
import os


def task1(q):
    print('我是task1进程,我的id号是:%s'%os.getpid())
    q.put('lqz is handsome')


def task2(q):

    # res=q.get()
    # print('我是task2进程,我的id号是:%s'%os.getpid(),res)
    print('我是task2进程,我的id号是:%s'%os.getpid())


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

    t1 = Process(target=task1, args=(q,))
    t1.start()
    t2 = Process(target=task2, args=(q,))
    t2.start()

    print(q.get())
---37---
posted @ 2020-08-24 15:10  1024bits  阅读(207)  评论(0编辑  收藏  举报