2010-09-12 41 views
3

我一直在考慮一個用於異步請求/響應的通用通用/可取消接口。的要求如下,它必須:設計一個通用的可取消異步操作接口

  • 支持異步調用
  • 成爲撤銷
  • 是通用
  • 支持請求/響應
  • 支持任一返回在當前線程或處理在該響應另一個迴應

所以這裏是我的第一個刺:

interface AsyncOperation<INPUT, OUTPUT> { 
    Future<OUTPUT> execute(INPUT in, AsyncCallback<OUTPUT> callback); 
} 

interface AsyncCallback<OUTPUT> { 
    void done(OUTPUT output); 
} 

用法:

// completely async operation 
operation.execute("Test", new AsyncCallback<String> { 
    public void done(String output) { 
     // process result... 
    } 
}); 

// sync operation with cancellation after timeout 
Future<String> future = operation.execute("Test", null); 
try { 
    String result = future.get(1000); 
} catch(TimeoutException ex) { 
    future.cancel(); 
} 

缺點

  • 它的複雜
  • 它僅支持單個請求參數 - 不用太在意這個
  • 單 '完成'意味着異常必須通過'完成'來傳達,這可以通過使用onSuccess和onException(和onFin ?盟友)中的AsyncCallback,但它會使它更加詳細

對於某些情況下,谷歌協議緩衝器服務方法遵循一個相對類似的模式:

void [methodname](RpcController controller, 
    [RequestClass] request, RpcCallback<[ResponseClass]> callback); 

更好的想法?

回答

1

您是否需要INPUT類型參數?那豈不是保持的輸入作爲狀態的操作對象,更容易爲:

void greet(final String name) { 
    new AsyncOperation<Object>() { 
     @Override Object doIt() { 
      System.out.println("Hello " + name + "!"); 
     } 
    }.execute(null); 
} 

這樣一來,他在一種安全的方式喜歡呼叫者可以傳遞儘可能多的參數。

此外,調用回調並返回未來似乎是一種奇怪的用法。你確定你需要嗎?您可以提供兩種執行方法,一種返回未來,另一種調用回調。

+0

你正確的,回調和返回未來有點奇怪,但它支持取消用例以及您可能想說的等待5秒的情況,如果操作完成返回操作的結果,如果不是,只是返回它是'忙處理'。該回調然後執行結果的實際處理。 – 2010-09-12 19:32:04

+0

狡猾的計劃擺脫了輸入參數限制。我記住的用例是能夠創建AsyncOperation的泛型實現,它們可以限制/限制使用的線程數量等。 – 2010-09-12 19:35:36

0

看看jetlang。它支持異步操作和請求 - 響應模型。下面是從他們的測試爲例:

@Test 
public void simpleRequestResponse() throws InterruptedException { 
    Fiber req = new ThreadFiber(); 
    Fiber reply = new ThreadFiber(); 
    req.start(); 
    reply.start(); 
    RequestChannel<String, Integer> channel = new MemoryRequestChannel<String, Integer>(); 
    Callback<Request<String, Integer>> onReq = new Callback<Request<String, Integer>>() { 
     public void onMessage(Request<String, Integer> message) { 
      assertEquals("hello", message.getRequest()); 
      message.reply(1); 
     } 
    }; 
    channel.subscribe(reply, onReq); 

    final CountDownLatch done = new CountDownLatch(1); 
    Callback<Integer> onReply = new Callback<Integer>() { 
     public void onMessage(Integer message) { 
      assertEquals(1, message.intValue()); 
      done.countDown(); 
     } 
    }; 
    AsyncRequest.withOneReply(req, channel, "hello", onReply); 
    assertTrue(done.await(10, TimeUnit.SECONDS)); 
    req.dispose(); 
    reply.dispose(); 
} 
+0

很酷。謝謝,會檢查出來。我喜歡Actor模型。對於請求/響應看起來有些麻煩,需要在其上添加取消? – 2010-09-12 19:43:12

+0

Jetlang不提供演員模型,儘管可以在通道,回調和它提供的請求響應系統的頂部構建它。 – 2010-09-12 20:05:19

+0

啊,好的,現在再看一遍,我明白你的意思了。我需要仔細看看Jetlang。 – 2010-09-24 21:28:42

0

好了,吮吸回答自己的問題,但我已經拿出了一組類,工程相當不錯了這一點:

// the main Async operation interface 
public interface AsyncOperation<OUTPUT, INPUT> { 
    public AsyncController execute(INPUT input, 
     AsyncCallback<OUTPUT> callback); 
} 

// the callback that gets called when the operation completes 
public interface AsyncCallback<OUTPUT> { 
    public void done(AsyncResult<OUTPUT> output); 
} 

// provides the ability to cancel operations 
public interface AsyncController { 
    void cancel(); 
} 

// this provides a convenient way to manage a response that is either a 
// value or an exception 
public class AsyncResult<VALUE> { 

    private final VALUE value; 
    private final Throwable throwable; 

    private AsyncResult(VALUE value, Throwable throwable) { 
     this.value = value; 
     this.throwable = throwable; 
    } 

    public AsyncResult(VALUE value) { 
     this(value, null); 
    } 

    public AsyncResult(Throwable throwable) { 
     this((VALUE) null, throwable); 
    } 

    public VALUE value() throws Throwable { 
     if(throwable != null) { 
      throw throwable; 
     } else { 
      return value; 
     } 
    } 
}