Python学习笔记-Day33-进程

内容大纲:

一、用python开启进程的两种方式

二、join控制子进程

三、daemon守护进程

四、Lock锁

五、Semaphore信号量

六、Event事件

 

 

一、用python开启进程的两种方式

multiprocessing包:是python中一个用于操作、管理进程的包,这个包几乎包含了进程有关的所有的子模块。大致可分为四个部分:创建进程部分、进程同步部分、进程池部分、进程之间数据共享部分。

multiprocessing.Process模块是专门用来创建进程的模块

1、直接使用Process类创建一个进程


import
os import time from multiprocessing import Process def func(): for i in range(10): time.sleep(0.5) print('子进程',os.getpid(),os.getppid()) if __name__ == '__main__': print('主进程',os.getpid(),os.getppid()) p = Process(target=func) # 实例化一个进程对象 p.start() # 子进程开始 for i in range(10): print('*'*i)

注意:为什么要用if __name__ == '__main__':?

在windows操作系统中由于没有fork(linux操作系统在创建进程的机制),在创建子进程的时候会自动import启动它的这个文件,而在import的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归子进程报错。所以必须把创建子进程的部分使用if __name__ == '__main__'判断保护起来,import的时候就不会递归运行了。

 

主进程与子进程之间的关系:

 

① 父进程和子进程的启动是异步的

② 父进程在执行完毕后不会立即结束程序,而是会等所有的子进程结束,父进程负责回收子进程的资源

 

 

# 创建多个子进程和给子进程传参
import  os
from multiprocessing import Process
def func(index):
    print('子进程%s:'%index,os.getpid(),os.getppid())
if __name__ == '__main__':
    for i in range(10):  # 创建多个子进程
        p = Process(target=func,args=(i,))  # 给子进程传参
        p.start()
    print('主进程:',os.getpid(),os.getppid())

 

#主进程与子进程之间数据是隔离的
from multiprocessing import Process
count = 100
def func():
    global count
    count -= 1
    print('子进程:',count)
if __name__ == '__main__':
    print('主进程:',count)
    p = Process(target=func)
    p.start()
结果:
99
100

2、用自定义类开启子进程

① 自定义一个类

② 继承Process

③ 一定要实现run()方法

④ 要传参数时,首先调用Proces中的init()方法才能进行传参

import os
from multiprocessing import Process
class Myprosess(Process):
    def __init__(self,arg):
        super().__init__()
        self.arg = arg
    def run(self):
        print('子进程%s:'% self.arg,os.getpid(),os.getppid())
if __name__ == '__main__':
    for i in range(10):
        p = Myprosess(i)
        p.start()
    print('主进程:',os.getpid(),os.getppid())

 

二、join控制子进程

join的作用:主进程的任务执行到某个阶段,需要等待子进程执行完毕后才能继续执行,否则就进入阻塞状态。没有join的时候,子进程和主进程的发生顺序是不可与预测的。

例如:模拟发邮件

import time
import random
from multiprocessing import Process
def func(index):
    time.sleep(random.random())
    print('第%s邮件已发送'%index)
if __name__ == '__main__':
    p_lst = []
    for i in range(10):
        p = Process(target=func,args=(i,))
        p.start()
        p_lst.append(p)
    for p in p_lst:
        p.join()
    print('10封邮件已全部发送完毕')

 

三、deamon守护进程

将一个子进程设置为守护进程之后

1、守护进程会随着主进程代码的执行完毕而结束

2、如果主进程的代码已经执行完,但是还有一些子进程还没执行完,主进程会等待子进程结束,守护进程直接结束

import time
from multiprocessing import Process
def func1():
    count = 1
    while True:
        time.sleep(0.5)
        print(count*'*')
        count += 1
def func2():
    print('func2 start')
    time.sleep(5)
    print('func2 end')
if __name__ == '__main__':
    p = Process(target=func1)
    p.daemon = True # 在start之前,将p设置为守护进程
    p.start()
    p2 = Process(target=func2)
    p2.start()
    time.sleep(3)
    print('主进程')

#结果:只打印了5次*
func2 start
*
**
***
****
*****
主进程
func2 end

 

四、Lock 互斥锁

Lock是一个类,在使用的时候要进行导入,和Process一样

Lock的作用:在异步的情况下,多个进程又可能修改同一份资源,就给这个修改的过程加上锁。

加锁降低了程序的效率,让原来能够同时执行的代码变成顺序执行,但是保证了数据的安全。

例如:火车票抢票

import json
import time
from multiprocessing import Process,Lock
def search(person):
    with open('ticket') as f:
        dic = json.load(f)
    time.sleep(0.2)  # 模拟网络延迟
    print('%s进行余票查询:'%person,dic['count'])

def get_ticket(person):
    with open('ticket') as f:
        dic = json.load(f)
    time.sleep(0.2)
    if dic['count'] > 0:
        dic['count'] -= 1
        print('%s买到票了'%person)
        time.sleep(0.2)
        with open('ticket','w') as f:
            json.dump(dic,f)
    else:
        print('%s没买到票'%person)
def main(person,lock):
    search(person)
    lock.acquire()
    get_ticket(person)
    lock.release()
if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        p = Process(target=main,args=(i,lock))
        p.start()

#结果是:
1进行余票查询: 6
2进行余票查询: 6
3进行余票查询: 6
7进行余票查询: 6
0进行余票查询: 6
6进行余票查询: 6
4进行余票查询: 6
9进行余票查询: 6
5进行余票查询: 6
8进行余票查询: 6
1买到票了
2买到票了
3买到票了
7买到票了
0买到票了
6买到票了
4没买到票
9没买到票
5没买到票
8没买到票

 

五、Semaphore信号量

信号量的作用:互斥锁Lock只允许一个线程更改数据,而信号量Semaphore同时允许一定数量的线程更改数据

信号量是计数器+锁实现的

例如:ktv允许同一时间4个人唱歌

import random
import time
from multiprocessing import Process,Semaphore
def ktv(person,sem):
    sem.acquire()
    print('\033[31m%s走进ktv\033[0m'%person)
    time.sleep(random.randint(1,5))
    print('\033[32m%s走出ktv\033[0m'%person)
    sem.release()
if __name__ == '__main__':
    sem = Semaphore(4) # 同时允许4个人做
    for i in range(10):
        p = Process(target=ktv,args=(i,sem))
        p.start()

 

六、Event 事件

Event的作用:用于主线程控制其他线程的执行,Event主要提供了3个方法:set、wait、clear

Event的处理机制:全局定义了一个'Flag',如果flag的值为false。那么当程序执行event.wait方法时就会阻塞,如果flag值为True,那么遇到event.wait方法时就不会阻塞

set():将’Flag‘设置为True

clear():将flag设置为false

is_set():判断flag当前属性是否为true

著名的例子:红绿灯

import time
import random
from multiprocessing import Process,Event
def traffic_light(e):
    print('\033[31m红灯亮\033[0m')
    while True:
        if e.is_set():  # if True,本来是绿灯亮,变为红灯,将flag设为false
            time.sleep(2)
            print('\033[31m红灯亮\033[0m')
            e.clear()
        else:
            time.sleep(2)
            print('\033[32m绿灯亮\033[0m')
            e.set()
def car(e,i):
    if not e.is_set(): # 红灯
        print('car%s在等待'%i)
        e.wait()  # 阻塞
    print('car%s通过了'%i)
if __name__ == '__main__':
    e = Event()
    p = Process(target=traffic_light,args=(e,))
    p.daemon = True  # 将p设为守护进程,主进程代码执行完毕就结束
    p.start()
    p_lst = []
    for i in range(20):
        time.sleep(random.randrange(0,3,2))
        p = Process(target=car,args=(e,i))
        p.start()
        p_lst.append(p)
    for p in p_lst:
        p.join()  # 当子进程结束时,主进程才开始执行

 

转载于:https://www.cnblogs.com/tian-tian/p/9677528.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,异常处理是非常重要的一部分。当程序运行时如果出现错误,如果没有异常处理,程序就会崩溃。为了避免这种情况,Python提供了异常处理机制。 在Python中,异常处理语句使用 `try` 和 `except` 关键字来实现。`try` 语句块中包含可能会发生异常的代码,如果这段代码出现了异常,则会跳转到 `except` 语句块中执行异常处理代码。 下面是一个简单的例子: ```python try: num = int(input("请输入一个整数:")) print(10/num) except ZeroDivisionError: print("除数不能为0") except ValueError: print("输入的不是整数") ``` 在上面的代码中,我们尝试将用户输入的字符串转换为整数,并将其用作除数计算 10/num。如果用户输入的是 0,则会触发 ZeroDivisionError 异常。如果用户输入的不是整数,则会触发 ValueError 异常。如果发生异常,则会跳转到对应的 except 语句块中执行处理代码。 除了可以指定具体的异常类型,也可以使用 `except Exception` 来捕获所有异常。例如: ```python try: num = int(input("请输入一个整数:")) print(10/num) except Exception as e: print("发生异常:", e) ``` 在上面的代码中,如果发生任何异常,都会跳转到 `except` 语句块中执行处理代码,并将异常信息打印出来。 除了 `try` 和 `except`,还有 `finally` 关键字,它指定的代码块无论是否发生异常都会执行。例如: ```python try: num = int(input("请输入一个整数:")) print(10/num) except Exception as e: print("发生异常:", e) finally: print("程序执行完毕") ``` 在上面的代码中,无论是否发生异常,都会执行 `finally` 中的代码,即输出“程序执行完毕”。 总之,在Python中,异常处理是非常重要的一部分,它可以有效避免程序崩溃,提高程序的健壮性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值