问题:从AppEngine的servlet调用Web服务(0.5-1.5秒/调用)的最佳方法是什么?阻止呼叫在AppEngine环境中是否可扩展?
上下文:我正在使用AppEngine和J2EE开发Web应用程序。应用程序调用Amazon Web服务以获取用户的一些信息。从我的asp.net经验来看,最好的方法就是使用异步http处理程序来防止IIS线程池中的饥饿。对于使用Servlet 2.5规范(3.0 is planned)的J2EE,此功能不可用。
现在我正在考虑使我的控制器(和servlet)线程安全并请求作用域。还有什么我可以做的吗?它甚至是J2EE + AppEngine环境中的问题吗?
编辑:我知道AppEngine和JAX-WS异步调用支持,但我不确定它如何与servlet环境一起使用。据我所知,要完成servlet请求,代码仍应等待异步WS调用完成(回调或其他)。 我假设使用同步原语执行此操作将阻止当前工作线程。因此,就线程被阻塞而言,为了服务另一个用户请求servlet容器需要在线程池中分配新线程,为堆栈分配新内存并浪费时间进行上下文切换。此外,当我们用完线程池中的线程时,请求可以阻止整个服务器。这些假设基于ASP.Net和IIS线程模型。它们适用于J2EE环境吗?
答案:在研究了Apache和GAE文档之后,似乎线程池中线程的缺乏并不是一个真正的问题。 Apache默认情况下有200个线程用于线程池(相比之下,asp.NET和IIS中有25个)。基于此,我可以推断JVM中的线程相当便宜。
如果确实需要异步处理或者servlet容器将用完线程,则可以重新设计应用程序以通过google channel api发送响应。 工作流程如下:
答案 0 :(得分:1)
正如您所看到的,servlet不支持使用单个线程来为多个并发请求提供服务 - 每个请求需要一个线程。执行HTTP调用的最佳方法是使用异步urlfetch,并在需要结果时等待该调用完成。这将阻止请求的线程,但没有避免 - 线程专用于当前请求,直到它终止,无论你做什么。
如果您不需要API调用的响应来提供用户的请求,则可以使用任务队列来脱机工作。
答案 1 :(得分:0)
使用fetchAsync是不是可以?
答案 2 :(得分:0)
看看这个,这可能会有所帮助
http://today.java.net/pub/a/today/2006/09/19/asynchronous-jax-ws-web-services.html
我不确定,如果你可以完全复制你在dot net中做的事情,那么你可以做的就是在加载时模拟它
如果你想这样做将是最好的选择而不是轮询在这种情况下是理想的Reverse Ajax / server push
编辑:现在我理解你的意思,我认为你可以让你的代码执行异步任务而不是等待来自异步本身的响应,只需将响应发送回用户。我有一个简单的线程,我将开始,但将等待它完成,因为我将响应发送回用户,同时使用会话令牌来跟踪请求
@Controller
@RequestMapping("/asyncTest")
public class AsyncCotroller {
@RequestMapping(value = "/async.html", method = RequestMethod.GET)
public ModelAndView dialogController(Model model, HttpServletRequest request)
{
System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
//start a thread (async simulator)
new Thread(new MyRunnbelImpl()).start();
//use this attribute to track response
request.getSession().setAttribute("asyncTaskSessionAttribute", "asyncTaskSessionAttribute");
//if you look at the print of system out, you will see that it is not waiting on //async task
System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
return new ModelAndView("test");
}
class MyRunnbelImpl implements Runnable
{
@Override
public void run()
{
try
{
Thread.sleep(5000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}