【第十五天】函数式与并行运算

第七章 函数式编程

7.1

1.Python中的函数式

函数式编程强调了函数的纯粹性(purity)
一个纯函数是没有副作用的(Side Effect),即这个函数的运行不会影响其他函数
为了达到纯函数标准,函数式编程要求其变量都是不可变更的

py并非完全的函数式编程语言,在py中,存在着可变更的对象,也能写出非纯函数
但如果我们借鉴函数式编程,尽量在编程中避免副作用,就会有许多好处
由于纯函数相互独立,我们不必担心函数调用对其他函数的影响
所以使用起来更加简单,另外,纯函数也方便进行并行化运算
在并行化编程时,我们经常担心不同进程之间相互干扰的问题
当多个进程同时修改一个变量时,进程的先后顺序会影响最终结果
如下面两个函数:

from threading import Thread
 
x = 5
 
def double():
    global x
    x = x*2

def plus_ten():
    global x
    x = x + 10

thread1 = Thread(target=double)
thread2 = Thread(target=plus_ten)
thread1.start()
thread2.start()
thread1.join()
thread2.join()

print(x) 
20

上面两个函数中使用了关键字global
global说明了x是一个全局变量
函数对全局变量的修改能被其他函数看到,因此也有副作用
如果两个进程并行地执行两个函数,函数的执行顺序不确定
则结果可能是double()中的x = x*2先执行,最终结果为20
也有可能是plus_ten()中的x = x + 10先执行,最终结果为30
这被称为竞跑条件(Race Condition),是并行编程中需要极力避免的

from threading import Thread
 
x = 5
 
def double():
    global x
    x = x*2

def plus_ten():
    global x
    x = x + 10

thread1 = Thread(target=double)
thread2 = Thread(target=plus_ten)
thread2.start()
thread1.start()
thread1.join()
thread2.join()

print(x) 
30

函数式编程消灭了副作用,即无形中消除了竞跑条件的可能性
因此,函数式编程天生适用于并行化运算

2.并行运算

上一节中,我们已经涉及到并行运算,所谓并行运算,是指多条指令同时执行
一般来说,一台单处理器计算机同一时间只能执行一条指令
这种每次执行一条指令的工作方式称为串行运算

大规模并行运算通常是在有多个主机组成的集群(Cluster)上进行的
主机之间可以借助高速的网络设备通信,一个集群造价不菲
然而,我们可以在单机上通过多进程或多线程的方式
模拟多主机的并行处理,即使一台单机中,也往往存在着多个运行中的程序
即所谓的进程,例如:我们在打开浏览器上网的同时
还可以流畅的听音乐,这给我们一个感觉,计算机在并行的进行上网和放音乐两个任务
事实上,单机的处理器按照‘分时复用’的方式,把计算能力分配给多个进程
处理器在进程间频繁切换,因此,即使处理器同一时间只能处理一个指令
但通过在进程间的切换,也能造成多个进程齐头并进的效果

从这个角度来说,集群和单机都实现了多个进程的并行运算
只不过,集群上的多进程分布在不同的主机,而单机的多进程存在于同一主机
并借着‘分时复用’来实现并行

下面是多进程编程的例子:

import multiprocessing

def proc1():
    return 999999**9999
def proc2():
    return 888888**8888
p1 = multiprocessing.Process(target=proc1)
p2 = multiprocessing.Process(target=proc2)

p1.start()
p2.start()

p1.join()
p2.join()

上面程序用了两个进程,进程的工作包含在函数中,分别是函数proc1()和函数proc2()
方法start()用于启动进程,而join()方法用于在主程序中等待相应进程完成

最后,我们要区分一下多进程和多线程,一个程序运行后
就成为一个进程,进程有自己的内存空间,用来存储自身的运行状态,数据和相关代码
一个进程一般不会直接读取其他进程的内存空间
进程运行过程中,可以完成程序描述的工作
但一个进程内部,又可以有多个称为‘线程’的任务
处理器可以在多个线程之间切换,从而形成并行的多线程处理
线程看起来和进程类似,但线程之间可以共享同一个进程的内存空间

你可能感兴趣的:(【第十五天】函数式与并行运算)