【问题标题】:Alternative to Thread.sleep() for performance? [closed]替代 Thread.sleep() 以获得性能? [关闭]
【发布时间】:2020-10-15 09:17:57
【问题描述】:

我在我的 Spring Boot 应用程序中执行一个函数,在 REST 请求中,我必须等待数据库中的变量具有“x”值,然后将响应返回给客户端。

我用Thread.sleep() 做了一段时间,但就性能而言,这是最好的方法吗?

带有 Thread.sleep 的代码:

   while(!peticionTmp.isRealizada()) {
        entityManager.clear();
        peticionTmp = peticionesRepository.findById(peticion_id);
        Thread.sleep(3000);
        System.out.println("Iteración! --> " + peticionTmp);
    }
    
    return peticionTmp.isRealizada();

我看到了可以用这个做什么:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor ();
     scheduler.schedule (() -> {
         / *
          * define work to be done inside this lambda
          * /
     }, diffTime, TimeUnit.MILLISECONDS);

但是暂时不知道怎么实现。

客户端发送请求,spring boot 应用程序将请求保存到数据库,现在另一个程序查看数据库以搜索请求,创建包含请求的服务并更改该请求的数据库中的一个字段, spring boot 当它看到它已更改该字段时,我将响应返回给客户端...

【问题讨论】:

  • 这似乎不是一个好主意...谁在更改数据库?如果您确定不会对数据库进行任何外部更改,则可以改为以可以通知更改(即可观察)的方式修改您的存储库,这样您就可以立即知道何时达到了所需的状态。
  • 我认为您的Thread.sleep 方法是正确的。但是,整体设计似乎不正确。当结果在数据库中时,您宁愿使用回调,而不是让连接保持打开状态等待结果。
  • @ACV "Spin-Wait" 通常被认为是一种反模式。虽然有时无法避免,但您应该尽可能避免。这似乎是一个可以避免的例子,但需要付出一些巨大的努力。
  • 您应该在 API 上使用长轮询或实现客户端通知,例如通过 websockets 或使用 HTPP2。阻止 REST 请求是一个糟糕的主意。
  • 但就性能而言,这样做是不是最好的方法 ...这是一个荒谬的说法。你担心什么样的表现? “最佳”总是是主观的。例如,请注意(就 CPU 周期而言)您的第二个选项更重。而第一个解决方案意味着:您等待 3 秒。这可能太长了,所以从理论上讲,这可能会增加某些用户的延迟。但我们不知道任何这样的细节。你知道。所以,这里没有人能告诉你什么是对你最好的

标签: java spring multithreading algorithm spring-boot


【解决方案1】:

正如其他人已经指出的那样,您的系统设计非常错误,因此您很可能面临比性能更大的问题。

现在,如果您真的必须提高现有脑损伤系统的性能,那么首先您需要定义性能。

对您而言,性能是什么?从客户的角度来看的响应时间?服务器上浪费的时钟周期数?可以同时服务的客户数量?

您令人难以置信的 3 整秒超时时间似乎表明您将性能视为浪费在服务器上的时钟周期。我们通常会选择很长的轮询周期,以极大地间隔轮询时刻,以减少每秒完成的工作量。

但这可能不是你的本意。您可能关心的是从客户端的角度来看的响应时间,因为 3 秒的超时意味着客户端将始终等待至少 3 秒,并且肯定是 3 秒的倍数。如果你想改进它,那么解决方案很简单:而不是Thread.sleep(3000)Thread.sleep(300) 甚至Thread.sleep(30)。现在,这将增加服务器上浪费的时钟周期数;那会是个问题吗?我们不知道,因为您还没有定义性能对您意味着什么。但我们所知道的是,你不可能拥有一切:大脑受损的系统设计必须做出妥协。

从 cmets 添加信息:

要解决这种情况,第一步是让服务器明确知道处理何时完成,而不是让服务器轮询来确定。有两种方法:

  1. 让服务器而不是外部应用程序进行处理。
  2. 让服务器启动一个外部应用程序来进行处理,并等待该应用程序终止,这样一旦外部应用程序终止,服务器就会知道处理完成。

那么,就对客户的响应而言,您有多种选择:

  1. 服务器可以在工作完成时保持请求等待,并在结束时返回结果。您目前正在使用Thread.Sleep() 完成此操作,但正如我在上面解释的那样,这需要消失,并替换为实际处理。如果处理必须由外部应用程序完成,则将替换为Process.WaitFor()
  2. 服务器可以返回“正在处理”的结果,然后客户端可以继续调用相同或其他 API 来轮询结果。
  3. 服务器可以使用spring boot的DeferredResult。

如果客户端是 Web 浏览器而不是 REST 客户端,那么您将有两个额外的选择:

  1. 服务器可以返回一个“正在处理”的结果,然后客户端可以使用 Ajax 接收工作完成的通知。
  2. 服务器可以返回“正在处理中;请刷新页面以查看是否准备就绪”的结果。

【讨论】:

  • 那么这个系统有什么替代品呢?如果客户提出请求,他必须得到一个响应,告诉他它是否顺利。请求可以持续几分钟,但这不是问题,因为将要完成的服务很长,而且他们已经知道了。但是当然,当程序做服务时,spring boot 必须等待程序的响应(查看数据库),或者可能还有另一种选择......(DeferredResult?)
  • 性能指的是服务器的负载(cpu、ram 等)
  • 替代方案是首先没有一个单独的“程序”来“提供服务”,而是从服务器内部“提供服务”(如果需要,启动一个外部程序,这样程序一返回,服务器就知道工作已经完成。)
  • 那么,就对客户端的响应而言,您有多种选择:a) 服务器可以在工作完成时保持请求等待,并在结束,或者 b) 服务器可以发送一个结果说“正在处理它”,然后使用 Ajax 通知客户端工作已经完成,或者 c) 服务器可以提供一个页面说“我们正在处理它,刷新页面看看是否完成”。
  • 是的,Spring Boot 的DeferredResult 也是一个非常不错的选择。但正如我在上面所写的,首先您必须在不涉及任何轮询的情况下向服务器提供有关何时完成处理的明确信息。任何涉及轮询的事情都是一个坏主意。总是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 2019-11-24
  • 2023-03-12
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多