美文网首页Python学习日志程序员
【第十五天】函数式与并行运算

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

作者: 人生苦短_我用Python | 来源:发表于2018-03-27 13:41 被阅读8次

    第七章 函数式编程

    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()方法用于在主程序中等待相应进程完成

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

    相关文章

      网友评论

        本文标题:【第十五天】函数式与并行运算

        本文链接:https://www.haomeiwen.com/subject/xrajcftx.html