具有限制/吞吐量控制的 Java 执行器

2022-09-01 06:47:44

我正在寻找一个Java执行器,它允许我指定限制/吞吐量/节奏限制,例如,在一秒钟内可以处理不超过100个任务 - 如果提交更多任务,它们应该排队并在以后执行。这样做的主要目的是避免在遇到外部 API 或服务器时遇到限制。

我想知道是基础Java(我怀疑,因为我检查过)还是其他可靠的地方(例如Apache Commons)提供这个,或者我是否必须编写自己的。最好是轻量级的东西。我不介意自己写,但如果在某个地方有一个“标准”版本,我至少想先看看它。


答案 1

看看番石榴率限制器

速率限制器。从概念上讲,速率限制器以可配置的速率分发许可证。如有必要,每个 acquire() 都会阻止,直到许可证可用,然后获取它。许可证一旦获得,就不必发放。速率限制器通常用于限制访问某些物理或逻辑资源的速率。这与 Semaphore 相反,Semaphore 限制并发访问的数量而不是速率(请注意,并发性和速率密切相关,例如参见 Little 定律)。

它的线程安全,但仍然.无论如何,可能值得一试。@Beta

您必须将每个调用都包装到 相对于速率限制器。对于更干净的解决方案,您可以为 .ExecutorExecutorService

来自 javadoc:

 final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
  void submitTasks(List<Runnable> tasks, Executor executor) {
    for (Runnable task : tasks) {
      rateLimiter.acquire(); // may wait
      executor.execute(task);
    }
  }

答案 2

Java Executor不提供这样的限制,只提供线程数量的限制,这不是你想要的。

一般来说,执行器无论如何都是限制此类操作的错误位置,它应该是在线程尝试调用外部服务器的时刻。例如,您可以通过线程在提交请求之前等待的限制信号量来执行此操作。

调用线程:

public void run() {
  // ...
  requestLimiter.acquire();
  connection.send();
  // ...
 }

同时,您计划一个(单个)辅助线程定期(如每 60 秒)释放获取的资源:

 public void run() {
  // ...
  requestLimiter.drainPermits();  // make sure not more than max are released by draining the Semaphore empty
  requestLimiter.release(MAX_NUM_REQUESTS);
  // ...
 }