我们已经讲过了什么是线程,那今天就来学习一下什么是进程,进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
进程是正在运行的程序的实例,简单的说就是比如我们自己在python文件中写了一些代码,这叫做程序,而运行这个python文件的时候就叫做进程

什么是并发

那什么是并发呢,并发就是在某个时间段内,两件或两件以上的事件轮流交替使用某一资源,其目的是提高效率;
需要注意的是并发和并行的区别:

  • 并发是指两个或多个事件在同一时间间隔发生,并行是指两个或者多个事件在同一时刻发生;
  • 并发是在同一实体上的多个事件,并行是在不同实体上的多个事件;

multiprocess模块

Python中提供multiprocess模块实现多进程并发,我们来看一下multiprocess模块的使用,通过一个实例来对比多线程和多进程程序运行对CPU的使用情况

import multiprocessing
import threading

def worker():
    number = 0
    for i in range(10000000):
        number += 1
        print('循环次数:{} number:{}'.format(i+1, number))

if __name__ == '__main__':
    for i in range(4):
        # 创建线程
        threading.Thread(target=worker, name='thread worker {}'.format(i)).start()

        # 创建进程
        multiprocessing.Process(target=worker, name='process worker {}'.format(i)).start()

分别启动线程和进程,运行代码,查看电脑的CPU的使用率,发现多进程占用内存多,切换复杂,CPU利用率低,多线程占用内存少,切换简单,CPU利用率高;

进程的一些对象方法

import multiprocessing
import threading
import time

def worker():
    number = 0
    for i in range(10000000):
        number += 1
        time.sleep(0.1)
        print(multiprocessing.current_process().name)  # 获取当前进程的名称
        print('循环次数:{} number:{}'.format(i+1,number ))
        
if __name__ == '__main__':
    for i in range(4):
        process = multiprocessing.Process(target=worker, name='process worker {}'.format(i))
        process.start()
        print(process.pid) # 获取进程的pid
        print(process.exitcode) # 获取退出状态码
        print(process.name)  # 获取进程名称
        time.sleep(30)
        print(process.terminate()) # 终止进程
  • multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了ProcessQueuePipeLock等 组件;
  • 可以使用multiprocessing.Process对象来创建一个进程,该进程可以运行在Python程序内部编写的函数;
  • process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建,有start()run()join()的方法;

进程并发:concurrent模块

from concurrent.futures import ProcessPoolExecutor
import requests

def fetch_url(url):
    result = requests.get(url=url, )
    return result.text
if __name__ == '__main__':
    # 创建10个线程队列的线程池
    pool = ProcessPoolExecutor(10)
    # 获取任务返回对象
    a = pool.submit(fetch_url, 'http://www.baidu.com')
    # 取出返回的结果
    x = a.result()
    print(x)

也可以使用上下文管理的方式

from concurrent.futures import ProcessPoolExecutor
import requests

def fetch_url(url):
    result = requests.get(url=url, )
    return result.text
if __name__ == '__main__':
    with ProcessPoolExecutor(max_workers=10) as pool:
        a = pool.submit(fetch_url, 'http://www.9xkd.com')
        print(a.result())
  • concurrent模块能够提供一个future的实例对象,实例对象提供了线程的执行器和进程的执行器;
  • submit():返回一个Future对象;
  • result():查看调用的返回结果;
  • done():如果任务成功执行或任务取消返回True;
  • cancel():取消任务;
  • running():如果任务正在执行返回True;
  • exception(): 获取执行抛出的异常;

守护进程实现(POSIX兼容)

  • 在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期 性的执行某种任务或等待处理某些发生的事件;
  • 由于在linux中,每个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终 端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭;
  • 但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运 行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端信息所打断,它从被执行的时候 开始运转,直到整个系统关闭才退出;

守护进程实现的步骤:

  • 父进程fork出子进程并exit退出;
  • 子进程调用setsid创建新会话;
  • 子进程调用系统函数chdir将根目录"/"成为子进程的工作目录;
  • 子进程调用系统函数umask将该进程的umask设置为0;
  • 子进程关闭从父进程继承的所有不需要的文件描述符;

对 os.fork( )的理解:

  • os.fork()返回两个值,一个是在当前父进程返回的,一个是在子进程中返回的;
  • 子进程返回的是0,父进程返回的是子进程的pid;
import os
pid = os.fork()
print(pid)
if pid == 0:
    print("我是子进程 pid={}, parent_pid={}".format(os.getpid(), os.getppid()))
else:
    print("我是父进程 pid={}, parent_pid={}".format(os.getpid(), os.getppid()))

参考:https://www.9xkd.com/user/pla...


Summer
83 声望9 粉丝

关于Python学习的一些小知识