由回调驱动的Java / Scala Future

时间:2015-06-20 17:04:06

标签: java scala playframework-2.0 akka nonblocking

简短版本:

如何创建在回调触发器上完成的Promise<Result>

长版:

我正在开发一个处理第三方SOAP服务的应用程序。来自用户的请求同时委托多个SOAP服务,聚合结果并发送回用户。

系统需要可扩展,并且应该允许多个并发用户。当每个用户请求最终触发大约10个Web服务调用并且每个呼叫阻塞大约1秒时,系统需要设计为具有非阻塞I / O.

我在Play Framework(Java)中使用Apache CXF来实现此系统。我已设法生成异步WS客户端代理并启用异步传输。我无法弄清楚当我委托给多个Web服务代理时如何返回Future to Play的线程,结果将作为回调获得。

选项1:使用返回Java Future的异步方法调用。

如此scala.concurrent.Future wrapper for java.util.concurrent.Future主题中所述,我们无法将Java Future转换为Scala Future。从Future获得结果的唯一方法是执行阻止调用者的Future.get()。由于CXF生成的代理返回Java Future,因此排除了此选项。

选项2:使用Scala Future。

由于CXF生成代理接口,我不确定是否有任何方法可以干预并返回Scala Future(AFAIK Akka使用Scala Futures)而不是Java Future?

选项3:使用回调方法。

CXF生成的返回Java Future的异步方法也需要一个回调对象,我想这会在结果准备就绪时提供回调。要使用这种方法,我需要返回一个等待我收到回调的Future。

我认为选项3 是最有希望的,虽然我对如何返回将在收到回调时完成的Promise没有任何想法。我可能有一个线程在while(true)等待并等待,直到结果可用。同样,我不知道如何在不阻塞线程的情况下进入wait

简而言之,我正在尝试构建一个正在进行大量SOAP Web服务调用的系统,其中每个调用都会占用大量时间。在许多并发Web服务调用的情况下,系统可能很容易耗尽线程。我正在努力寻找一种基于非阻塞I / O的解决方案,它可以同时允许许多正在进行的Web服务调用。

1 个答案:

答案 0 :(得分:2)

选项3看起来不错:)开始使用几个进口......

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace wmic_forms
{
  public partial class Form1 : Form
  {
    public Form1()
    {
        InitializeComponent();
    }
    public string x;
    private void button1_Click(object sender, EventArgs e)
    {
        ProcessStartInfo psi = new ProcessStartInfo();
        psi.FileName = "C:\\ken.bat";
        Process p = Process.Start(psi);
        string strOutput = p.StandardOutput.ReadToEnd();
        //p.WaitForExit();
        psi.UseShellExecute = false;
        psi.RedirectStandardOutput = true;
        psi.Arguments = textBox1.Text;

        MessageBox.Show(strOutput);
        //Console.WriteLine(strOutput);
        //Console.ReadLine();
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
       //my input text box for IP
        x = textBox1.Text;
    }
  }
}

并且,为了说明这一点,这里是一个采用回调的模拟CXF API:

import scala.concurrent.{Await, Promise}
import scala.concurrent.duration.Duration

创建一个promise,使用promise作为回调调用API:

def fetch(url: String, callback: String => Unit) = {
  callback(s"results for $url")
}

然后,您可以将val promise = Promise[String] fetch("http://corp/api", result => promise.success(result)) promise.future的实例带入您的Play应用。

要测试它,你可以这样做:

Future

将阻止等待结果,此时您应该在控制台中看到“http://corp/api的结果”。