1.进程与程序
2.并发与并行
3.多进程创建方式
4.互斥锁

假设在一个时间段内有很多任务要做:python备课的任务,写书的任务,交女朋友的任务,王者荣耀上分的任务,但同一时刻只能做一个任务(cpu同一时间只能干一个活),如何才能玩出多个任务并发执行的效果?备一会课,再去跟二娃子的女朋友聊聊天,再去打一会王者荣耀….这就保证了每个任务都在进行中

1.进程与程序

程序仅仅是一堆代码,进程指的是程序的运行过程
注意:同一个程序执行两次,也是两个进程
进程:正在进行的一个过程,是一个任务,或者说是一个资源调度的集合。

2.并发与并行

无论是并行还是并发,在用户看来都是’同时’运行的,不管是进程还是线程,都只是一个任务而已,真实干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务。

  一、并发:伪并行,即看起来多个进程像在同时运行。单个cpu+多道技术可实现并发。

  二、并行:多个进程同时运行,只有具备多个cpu才能实现。
并发,并行,串行

3.多进程创建方式

注意:在windows中Process()必须放到# if __name__ == '__main__':下
进程创建格式:target表示函数名,args=(参数一,参数二,…,),参数最后一定要保留一个逗号
p = Process(target=task, args=(‘子进程1’,))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from multiprocessing import Process
import time


def task(name):
print("%s is running" % name)
time.sleep(3)
print("%s is done" % name)

if __name__ == '__main__':
# 创建进程
p = Process(target=task, args=('子进程1',)) # 得到对象
# 启动进程
p.start()
print("这是主进程")

3.1 Process类的方法和属性介绍

方法 详解
p.start(): 启动进程,并调用该子进程中的p.run()
p.run(): 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate(): 强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive(): 如果p仍然运行,返回True
p.join([timeout]): 主线程等待p线程终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间
Process属性 详解
p.daemon: 默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name: 进程的名称
p.pid: 进程的pid
p.exitcode: 进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey: 进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串

3.2 进程之间的内存空间是隔离的

3.3 Process对象的join方法

  1. join方法:优先运行子进程,主进程卡在原地,子进程结束后,运行主进程后面的代码。案例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from multiprocessing import Process
    import time, os

    def task():
    print('%s is running, parent id is <%s>' % (os.getpid(), os.getppid())) # 进程和父进程查看方式
    time.sleep(3)
    print("%s is done, parent id is <%s>" % (os.getpid(), os.getppid()))

    if __name__ == '__main__':
    p = Process(target=task, )
    p.start()

    p.join() # 优先运行子进程,主进程卡在原地
    print('主进程', os.getpid(), 'pycharm ID', os.getppid())
    print(p.pid) # 子进程运行完,变为僵尸进程,主进程仍能够查到子进程的pid,当主进程结束后,所有僵尸子进程将被丢掉。
    """
    is running, parent id is <827>
    is done, parent id is <827>
    主进程 827 pycharm ID 504
    """
  2. 使用join方法实现并发执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from multiprocessing import Process
    import time

    def task(name ,n):
    print('%s is running' % name)
    time.sleep(n)

    if __name__ == '__main__':
    start = time.time()
    p1 = Process(target=task, args=("子进程1",5,))
    p2 = Process(target=task, args=("子进程2",3,))
    p3 = Process(target=task, args=("子进程3",2,))
    p1.start()
    p2.start()
    p3.start()
    # 再添加join函数前,主程序的执行输出次序是完全随机的,需要加join()保证主程序等到在子进程之后执行完成
    p1.join()
    p2.join()
    p3.join()
    # 以上并非串行执行,实际是并发执行,只是约束了主程序要等在子程序后结束
    # print('主进程', os.getpid(), 'pycharm ID', os.getppid())
    print("主进程", (time.time()-start))
    """
    子进程1 is running
    子进程2 is running
    子进程3 is running
    主进程 5.010260343551636 # 主程序只等了5秒,说明确实是并发执行
    """
  3. 使用join方法实现多进程串行执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from multiprocessing import Process

    def task(name ,n):
    pass

    if __name__ == '__main__':

    p1 = Process(target=task, args=("子进程1",5))
    p2 = Process(target=task, args=("子进程2",3))
    p3 = Process(target=task, args=("子进程3",2))
    # 串行执行
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
    print("我是主进程")
  4. 守护进程

主进程创建守护进程:
  一:守护进程会在主进程代码执行结束后就终止,主进程代码运行结束,守护进程立即死亡

  二:守护进程内无法再开启子进程,否则抛出异常

1
2
3
4
5
if __name__ == '__main__':
p = Process(target=task, args=('子进程', ))
p.daemon=True # 守护进程一定要在进程开启前,即p.start()开启前设置
p.start()
print("我是主进程")

4.互斥锁

进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱
互斥锁的原理:就是把并发改成穿行,降低了效率,但保证了数据安全不错乱

1
2
3
4
5
6
7
8
9
10
11
def task():
# 获得锁
lock.acquire()
...
# 释放锁
lock.release()
if __name__ == '__main__':
lock = Lock() # 只实例化一次,并传给子进程,要保证所有进程用同一把锁
for i in range(3):
p = Process(target=task, args=('进程%s' % i, lock,)) # 传递给子进程的锁
p.start()

 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议