OS模块

1.system函数是最简单创建进程的方式,函数只有一个参数,就是要执行的命令。

举个简单的例子:

import os
if os.name == 'nt':
    return_code = os.system('dir')
else:
    return_code = os.system('ls')

#判断命令返回值是否为0,为0则表明运行成功
if return_code == 0:
    print('Run success!')
else:
    print('Something wrong!')

比os.system函数更复杂一点的是exec系列的函数。

然后还有一个os.fork函数,可以调用系统api并且创建子进程。但是fork在Windows上并不存在,在Linux和Mac可以成功使用。因为手头没有Linux的机器,就没尝试这个。

subprocess模块

subprocess.call也可以调用外部命令。传入的参数可以是字符串也可以是序列

然后,subprocess.check_call用法与call基本相同,只是,如果外部调用的程序返回码不为0,那么就会抛出CalledProcessError。

import os
import subprocess
try:
    if os.name == 'nt':
        return_code = subprocess.check_call(['cmd', '/C', 'test command'])
    else:
        return_code = subprocess.check_call(['ls', '-1'])
except subprocess.CalledProcessError as e:
    print('Sonething wrong!', e)

subprocess的Popen对象

Popen对象提供了功能更丰富的方式来调用外部命令。前面介绍的subprocess.call和check_call其实调用的都是Popen对象,再进行封装。

关于Popen对象,举个例子吧

import os
import subprocess

if os.name == 'nt':
    ping = subprocess.Popen('ping -n 5 www.baidu.com', shell=True, stdout=subprocess.PIPE)
else:
    ping = subprocess.Popen('ping -c 5 www.baidu.com', shell=True, stdout=subprocess.PIPE)

#等待命令执行完毕
ping.wait()
#打印外部命令的进程id
print(ping.pid)
#打印外部命令的返回码
print(ping.returncode)
#打印外部命令的输出内容
print(ping.stdout.read().decode('GBK'))

multiprocessing.Process

上面我们讲到的都是调用外部命令(当然也可以调用程序自身)。

这个multiprocessing.Process对象提供了多进程的功能。使用方法与threading模块的多线程类似。但是,multiprocessing模块创建的是子进程而不是子线程。所以可以有效避免全局解释器锁和有效地利用多核CPU的性能。

multiprocessing.Process使用方法与threading.Thread类似

上代码!

from multiprocessing import Process
import os


def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())


def f(name):
    info('function f')
    print('hello', name)


if __name__ == '__main__':
    info('main line')
    p = Process(target=f, args=('零一',))
    p.start()
    p.join()

与Thread一样,我们使用target参数指定需要执行的函数。用args参数传递元组来作为函数的参数传递。multiprocessing.Process使用起来与Thread没啥区别。甚至我们也可以写一个继承于Process的子类并在其中实现run方法。

这个代码就和Thread的类似了

from multiprocessing import Process
import os


class MyProcess(Process):
    def __init__(self):
        super(MyProcess, self).__init__()

    def run(self):
        print('Module name:', __name__)
        print('Parent process:', os.getppid())
        print('process id:', os.getpid())


def main():
    processes = []
    for i in range(5):
        process = MyProcess()
        processes.append(process)
    for i in range(5):
        processes[i].start()
    for i in range(5):
        processes[i].join()


if __name__ == '__main__':
    main()

需要注意的是,在Unix平台上,在某个进程终结之后,该进程需要被其父进程调用wait,否则会成为僵尸进程(Zombie).所以有必要对每个Process对象调用join()方法。

multiprocessing.Queue可以帮我们实现进程同步

这个用法和线程之中的Queue是类似的,但是有一点点要注意的是,要把Queue对象传递给子进程,否则子进程中的Queue就一直是空的。这是因为,进程之间不能共享变量而线程之间可以共享变量。

上代码

from multiprocessing import Process, Queue
import os

result_queue = Queue()


class MyProcess(Process):
    def __init__(self, q):
        super(MyProcess, self).__init__()
        #获取队列,这是与线程不同的地方!一定要注意!!!!!!
        self.q = q

    def run(self):
        opt = 'module name %s\n' % __name__
        opt += 'parent process %d\n' % os.getppid()
        opt += 'process id %d' % os.getpid()
        self.q.put(opt)


def main():
    processes = []
    for i in range(5):
        processes.append(MyProcess(result_queue))
    for i in range(5):
        processes[i].start()
    for i in range(5):
        processes[i].join()
    while not result_queue.empty():
        opt = result_queue.get()
        print(opt)


if __name__ == '__main__':
    main()

对于需要进行密集计算的代码,我们需要使用进程模块以提高效率。我们还在上面介绍了队列、线程同步等概念,在并行编程的时候一定要注意保持数据的一致性,否则可能出现一些意外的结果。

你也可能喜欢

发表评论