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