英文:
Alternative to Thread.sleep() for performance?
问题
我正在我的Spring Boot应用程序中编写一个函数,在REST请求中,我必须等待来自数据库的变量具有'value x',然后将响应返回给客户端。
我使用了Thread.sleep()
和一个while循环来实现,但从性能的角度来看,这是否是最佳方法?
使用Thread.sleep()
的代码:
while (!peticionTmp.isRealizada()) {
entityManager.clear();
peticionTmp = peticionesRepository.findById(peticion_id);
Thread.sleep(3000);
System.out.println("Iteration! --> " + peticionTmp);
}
return peticionTmp.isRealizada();
我了解到也可以使用以下方法:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(() -> {
/*
* 在这个lambda内部定义要执行的任务
*/
}, diffTime, TimeUnit.MILLISECONDS);
但我不知道如何在while循环中实现它。
客户端发送一个请求,Spring Boot应用程序将请求保存到数据库中,然后另一个程序会查看数据库以查找请求,执行包含请求的服务,并更改数据库中该请求的一个字段。当Spring Boot应用程序看到已更改该字段时,会将响应返回给客户端...
英文:
I am doing a function in my Spring Boot application where in a REST request, I have to wait for a variable from the DB to have 'x' value and then return the response to the client.
I did it with Thread.sleep()
in a while, but is it the best way to do it in terms of performance?
Code with Thread.sleep:
while(!peticionTmp.isRealizada()) {
entityManager.clear();
peticionTmp = peticionesRepository.findById(peticion_id);
Thread.sleep(3000);
System.out.println("Iteración! --> " + peticionTmp);
}
return peticionTmp.isRealizada();
I saw what could be done with this:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor ();
scheduler.schedule (() -> {
/ *
* define work to be done inside this lambda
* /
}, diffTime, TimeUnit.MILLISECONDS);
But I don't know how to implement it in the while.
The client sends a request, the spring boot application saves the request to the DB, now another program looks at the DB in search of requests, makes the service that contain the request and changes a field in the database of that request, the spring boot when it sees that it has been changed that field, I return the response to the client ...
答案1
得分: 4
正如其他人已经指出的,你手头的系统设计非常错误,所以你很可能存在比性能更大的问题。
现在,如果你真的必须提升现有糟糕系统的性能,首先你需要定义性能。
对于你来说,什么是性能?是客户端从响应的时间?是服务器上浪费的时钟周期数量?是可以同时服务的客户端数量?
你令人难以置信的长达3秒的超时似乎表明你认为性能是服务器上浪费的时钟周期数量。当我们希望大大间隔轮询的时候,我们通常会选择非常长的轮询周期,以减少每秒所执行的工作量。
但那可能不是你的意图。你可能真正关心的是客户端的响应时间,因为3秒的超时意味着客户端将至少等待3秒,当然也可能是3秒的倍数。如果你想改进这一点,解决方案很简单:不要使用 Thread.sleep(3000)
,而是使用 Thread.sleep(300)
或甚至 Thread.sleep(30)
。现在,这将增加服务器上浪费的时钟周期数量;这会成为一个问题吗?我们不知道,因为你没有定义性能对你来说意味着什么。但我们知道的是,你不能得到所有的东西:一个有缺陷的系统设计将不得不做出妥协。
从评论中添加信息:
要解决这种情况,第一步是让服务器明确知道处理何时完成,而不是让服务器进行轮询来确定。有两种方法可以做到这一点:
- 让服务器执行处理,而不是使用外部应用程序。
- 让服务器启动一个外部应用程序来进行处理,并且等待该应用程序终止,这样一旦外部应用程序终止,服务器就知道处理已完成。
然后,就客户端的响应而言,你有几种选择:
- 服务器在工作进行中时可以让请求等待,然后在结束时返回结果。你目前使用
Thread.Sleep()
来完成这个操作,但正如我上面解释的,这需要消失,并且需要被实际的处理所替代。如果处理必须由外部应用程序完成,那么它将被Process.WaitFor()
替代。 - 服务器可以返回一个结果,显示“正在处理中”,然后客户端可以继续调用相同的或另一个 API 来轮询结果。
- 服务器可以利用 Spring Boot 的 DeferredResult。
如果客户端是 Web 浏览器而不是 REST 客户端,那么你将有两个额外的选项:
- 服务器可以返回一个结果,显示“正在处理中”,然后客户端可以使用 Ajax 来接收通知,表示工作已完成。
- 服务器可以返回一个结果,显示“正在处理中;请刷新页面以查看是否准备就绪。”
英文:
As others have already pointed out, you have a very wrong system design in your hands, so you most likely have far bigger problems than performance.
Now, if you really must improve the performance of your existing brain-damaged system, then first of all you need to define performance.
What is performance for you? Response time from the point of view of the client? Number of clock cycles wasted on the server? Number of simultaneous clients that can be served?
Your mind-bogglingly long timeout of 3 entire seconds seems to indicate that you perceive performance as clock cycles wasted on the server. We usually choose very long polling periods when we want to greatly space out the moments of polling, so as to reduce the amount of work done per second.
But that was probably not your intention. What you are probably concerned about is response time from the point of view of the client, since a timeout of 3 seconds means that the client will always wait at least 3 seconds, and certainly a multiple of 3 seconds. If you want to improve that, then the solution is simple: instead of Thread.sleep(3000)
do Thread.sleep(300)
or even Thread.sleep(30)
. Now, that will increase the number of clock cycles wasted on the server; would that be a problem? We don't know, because you have not defined what performance means for you. But what we do know is that you cannot have everything: a brain-damaged system design will have to make compromises.
Adding information from the comments:
To fix this situation the first step is to give the server definitive knowledge of when the processing is complete, instead of having the server do polling to determine that. There are two approaches to this:
- Have the server do the processing instead of an external application.
- Have the server launch an external application to do the processing, and wait for that application to terminate, so that as soon as the external application terminates, the server knows that the processing is done.
Then, you have a number of alternatives as far as the response to the client is concerned:
- The server can keep the request waiting while the work is being done, and return a result at the end. You are currently accomplishing this with
Thread.Sleep()
, but as I have explained above, this needs to go away, and to be replaced with the actual processing. If the processing must be done by an external application, then it will be replaced byProcess.WaitFor()
- The server can return a result saying "working on it" and then the client can keep calling the same or another API to poll for the results.
- The server can make use of spring boot's DeferredResult.
If the client was a web browser instead of a REST client, then you would have two additional options:
- The server can return a result saying "working on it" and then the client can use Ajax to receive notification that the work is done.
- The server can return a result saying "working on it; please refresh the page to see if it is ready."
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论