Java 如何根据用户定义的参数执行节流?

Java 如何根据用户定义的参数执行节流?,java,multithreading,scala,throttling,Java,Multithreading,Scala,Throttling,我正在以用户在多线程环境中定义的批量大小写入内存中的分布式数据库。但我想将写入的行数限制为每秒1000行。这个要求的原因是我的生产者写得太快,消费者遇到了叶内存错误。在批处理记录时是否有任何标准做法来执行节流 dataStream.map(line => readJsonFromString(line)).grouped(memsqlBatchSize).foreach { recordSet => val dbRecords = recordSet.map(m =>

我正在以用户在多线程环境中定义的批量大小写入内存中的分布式数据库。但我想将写入的行数限制为每秒1000行。这个要求的原因是我的生产者写得太快,消费者遇到了叶内存错误。在批处理记录时是否有任何标准做法来执行节流

dataStream.map(line => readJsonFromString(line)).grouped(memsqlBatchSize).foreach { recordSet =>
      val dbRecords = recordSet.map(m => (m, Events.transform(m)))
      dbRecords.map { record =>
        try {
          Events.setValues(eventInsert, record._2)
          eventInsert.addBatch
        } catch {
          case e: Exception =>
            logger.error(s"error adding batch: ${e.getMessage}")
            val error_event = Events.jm.writeValueAsString(mapAsJavaMap(record._1.asInstanceOf[Map[String, Object]]))
            logger.error(s"event: $error_event")
        }
      }

      // Bulk Commit Records
      try {
        eventInsert.executeBatch
      } catch {
        case e: java.sql.BatchUpdateException =>
          val updates = e.getUpdateCounts
          logger.error(s"failed commit: ${updates.toString}")
          updates.zipWithIndex.filter { case (v, i) => v == Statement.EXECUTE_FAILED }.foreach { case (v, i) =>
            val error = Events.jm.writeValueAsString(mapAsJavaMap(dbRecords(i)._1.asInstanceOf[Map[String, Object]]))
            logger.error(s"insert error: $error")
            logger.error(e.getMessage)
          }
      }
      finally {
        connection.commit
        eventInsert.clearBatch
        logger.debug(s"committed: ${dbRecords.length.toString}")
      }
    }
我希望如果可以将用户定义的参数作为throttleMax传递,并且如果每个线程写入的总记录达到throttleMax,则会调用thread.sleep()1秒。但这将使整个过程非常缓慢。是否有其他有效方法可用于将数据加载限制为1000行/秒?

正如其他人所建议的(请参阅问题的评论),您有比此处限制更好的选择。但是,您可以使用一些简单的代码来限制Java中的操作,如下所示:

/**
 * Given an Iterator `inner`, returns a new Iterator which will emit items upon
 * request, but throttled to at most one item every `minDelayMs` milliseconds.
 */
public static <T> Iterator<T> throttledIterator(Iterator<T> inner, int minDelayMs) {
    return new Iterator<T>() {
        private long lastEmittedMillis = System.currentTimeMillis() - minDelayMs;

        @Override
        public boolean hasNext() {
            return inner.hasNext();
        }

        @Override
        public T next() {
            long now = System.currentTimeMillis();
            long requiredDelayMs = now - lastEmittedMillis;
            if (requiredDelayMs > 0) {
                try {
                    Thread.sleep(requiredDelayMs);
                } catch (InterruptedException e) {
                    // resume
                }
            }
            lastEmittedMillis = now;

            return inner.next();
        }
    };
}
/**
*给定迭代器'inner',返回一个新的迭代器,该迭代器将在
*请求,但限制为每'minDelayMs'毫秒最多一项。
*/
公共静态迭代器throttleeditor(迭代器内部,int minDelayMs){
返回新的迭代器(){
private long lastEmittedMillis=System.currentTimeMillis()-minDelayMs;
@凌驾
公共布尔hasNext(){
返回inner.hasNext();
}
@凌驾
公共交通工具{
long now=System.currentTimeMillis();
long requiredDelayMs=now-lastEmittedMillis;
如果(要求Delayms>0){
试一试{
线程。睡眠(必需的delayms);
}捕捉(中断异常e){
//恢复
}
}
lastEmittedMillis=现在;
返回inner.next();
}
};
}

上面的代码使用了
线程。sleep
,因此不适合在反应式系统中使用。在这种情况下,您可能希望使用该系统中提供的油门实现,例如

了解reactiveX。它可以做你想做的事情:你可以用它来做我想用的scala。首先,它是基于拉而不是推的。因此,您可以实现一种与执行过程中最慢的步骤一样快的方法。节流与
.delayOnNext(持续时间:FiniteDuration)
一样简单。