zoukankan      html  css  js  c++  java
  • FastMessenger 帮助你把顺序程序中的部分改写成并发

    在日常编程中,很多程序由多个小一点的部分组成。这个程序运行这些小的部分,获得它们的结果,并用这些结果来计算出整个程序的结果。很多算法也是这样的,一个算法有几个步骤,每一步的结果都对最终结果有影响。一般来说这样的程序和算法都是顺序型的,除非是专门的并发算法,或者是有时间要求的高性能程序。

    如果要你去编写或重构一个这样的顺序程序,但又包含并发的部分,你会需要什么样的编程技术呢?现代的语言象Java和C#,都有内置的线程支持。但问题是线程是一种低级(接近机器硬件)的技术,大部分时间经常是花在改程序结构来容纳线程,而不是让线程来为你的程序服务。

    幸运地是Java和C#大约从2005开始提供更完善的编程技术。比如Java提供了 ExecutorService,Callable,和 Future。C#提供了 

    IAsyncResult 设计模式。

    Java: http://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html
    C#: http://msdn.microsoft.com/en-us/library/ms228963.aspx

    本文的重点是通过一个例子来说明 FastMessenger 如何帮助程序员将顺序程序的部分重构成并发的,所以不会涉及Java和C#的方案,也不涉及将 FastMessenger 和它们比较。这些都留给以后的文章再谈。

    本文用到的例子 Fibonacci 是从一本计算机教科书里来的,书名是“Introduction to Programming in Java”。这本是Java书,但不表示我在这里谈的光是Java的东西。实际上 FastMessenger (implementation)自己在Java,C#和JavaScript都已经实现了。你完全可以用这里谈到的技术去改写你的C#程序。

    教科书: http://introcs.cs.princeton.edu/java/home/
    源程序: http://introcs.cs.princeton.edu/java/92symbolic/Fibonacci.java.html

    两个大的BigInteger相乘是非常慢的,所以我的目标是让这个例子里的乘法并发运行。我将改写源程序中的这句。让这句里的两个乘法并发执行。

    BigInteger result = fibonacci(n2).multiply(fibonacci(n2)).add(fibonacci(n3).multiply(fibonacci(n3)));

    这句太长了,在重构前,我把它分开了来写,让它更易读。

    复制代码
    BigInteger Fn2 = fibonacci (n2);
    BigInteger Fn2xn2 = Fn2.multiply (Fn2);
    
    BigInteger Fn3 = fibonacci (n3);
    BigInteger Fn3xn3 = Fn3.multiply (Fn3);
    
    BigInteger result = Fn2xn2.add (Fn3xn3);
    复制代码

    现在开始用 FastMessenger 来重构了。第一步是写一个新的worker class,它要做的就是两个BigInteger的乘法。

    public class FastMessengerWorker {
        public BigInteger multiply (BigInteger a, BigInteger b) {
            return a.multiply (b);
        }
    }

    第二步是在主程序 Fibonacci 里加一个 FastMessenger。因为源例用的是 static method 的,我也只好使用 static 了。FastMessenger 使用一个称为“中间人”的主结构,呼叫方(caller)和被呼叫方(callee or receiver)只能通过这个中间人来进行。除了 FastMessenger 的 instance,第二步的代码里还建立并注册了两个 worker。

    复制代码
    private static IMessenger messenger;
    static {
        FastMessengerWorker[] workers = new FastMessengerWorker[] { new FastMessengerWorker (), 
                new FastMessengerWorker () };
        messenger = new Messenger ();
        messenger.registerReceiver (workers, "worker", "multiply");
    }
    复制代码

    最后一步,改写原程序,让它通过 FastMessenger 来让两个 worker 干活。

    复制代码
    BigInteger Fn2 = fibonacci (n2);
    IResponse<BigInteger> Fn2xn2 = messenger.sendRequest ("worker", "multiply", Fn2, Fn2);
    
    BigInteger Fn3 = fibonacci (n3);
    IResponse<BigInteger> Fn3xn3 = messenger.sendRequest ("worker", "multiply", Fn3, Fn3);
    
    BigInteger result = Fn2xn2.get ().add (Fn3xn3.get ());
    复制代码

    和前面分行的原程序比起来,行数和结构都没有变化,但却变成并发的了。FastMessenger 为每一个 caller 的 request 都返回一个 IResponse。一方面这个 caller 继续执行下面的语句,另一方面,FastMessenger 开始调用一个 worker 来做乘法。那 caller 何时何地接受乘法的结果呢?就在 caller 调用 IResponse.get() 的那时那一行。这个 get() 是阻塞式的,要等乘法真的完成了有了结果才会返回。

    这里将列一下这个例子里涉及到的 FastMessenger 的功能和特性(1.4版后)。下载地址在http://java.net/projects/fastmessenger/downloads

    Receiver 里保证是单线程模式

    Receiver首先要在FastMessenger注册,然后FastMessenger会根据收到的request来调用一个receiver instance来处理这个request。FastMessenger将保证在一个receiver instance返回之前不会再次重入调用。

    内置的负荷平衡

    一个receiver是由注册时的 id 来区分的,一个 id 一个receiver,但一个 id 可以有一个以上的instance。因为一个instance一次只能处理一个request,所以当所有的instance都忙的时候,多余的request就只能等待了。

    使用reflection来提供参数化的message以及用method names代替message ports

    FastMessenger 1.4 以前的版本只支持 IReceiver 的sub class。那样的话有点不方便,因为method signature是固定的。最近我为了易用性,加了reflection,虽然损失了编译时的类型检查但至少让用户多了一个选择。从上面的代码,你们一定会同意真是太方便了。

    可定制的返回类型

    和参数类型一样,返回类型也是可以定制的,所以当caller调用 IResponse.get() 的时候,显得非常好用。


    原文地址:http://weblogs.java.net/blog/rexyoung/archive/2012/08/05/fastmessenger-makes-coding-concurrent-sub-tasks-main-task-breeze

     
     
     
  • 相关阅读:
    CentOS7 安装 MySQL 5.7
    Centos7 安装 opencv
    nginx编译支持HTTP2.0
    CentOS 6.5 安装 ffmpeg
    parted 4T磁盘
    nginx upstream
    linux rar 解压忽略带密码压缩包
    那些实用的Nginx规则
    linux 两台服务器共享目录NFS实现
    redis集群搭建
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2625726.html
Copyright © 2011-2022 走看看