Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 等待Scala的未来完成,然后继续下一个_Multithreading_Scala_Akka Stream - Fatal编程技术网

Multithreading 等待Scala的未来完成,然后继续下一个

Multithreading 等待Scala的未来完成,然后继续下一个,multithreading,scala,akka-stream,Multithreading,Scala,Akka Stream,我有一个500000个元素的列表和一个包含20个消费者的队列。消息以不同的速度处理(1、15、30、60秒;3、50分钟;3、16小时或更长。24小时是超时)。我需要消费者的回复,以便对数据进行一些处理。我将使用ScalaFuture进行此操作,并使用基于事件的onComplete 为了不让队列泛滥,我想向队列发送前30条消息:20条消息将由消费者挑选,10条消息将在队列中等待。当一个Futures完成时,我想向队列发送另一条消息。你能给我一个实现这一目标的方法吗?这可以通过Akka Strea

我有一个500000个元素的列表和一个包含20个消费者的队列。消息以不同的速度处理(1、15、30、60秒;3、50分钟;3、16小时或更长。24小时是超时)。我需要消费者的回复,以便对数据进行一些处理。我将使用Scala
Future
进行此操作,并使用基于事件的
onComplete

为了不让队列泛滥,我想向队列发送前30条消息:20条消息将由消费者挑选,10条消息将在队列中等待。当一个
Future
s完成时,我想向队列发送另一条消息。你能给我一个实现这一目标的方法吗?这可以通过Akka Streams实现吗

这是错误的,我只是想告诉你我想要什么:

private def sendMessage(ids: List[String]): Unit = {
  val id = ids.head

  val futureResult = Future {
    //send id among some message to the queue
  }.map { result =>
    //process the response
  }

  futureResult.onComplete { _ =>
    sendMessage(ids.tail)
  }
}

def migrateAll(): Unit = {
  val ids: List[String] = //get IDs from the DB

  sendMessage(ids)
}

这是我用于此类任务的代码

class RateLimiter(semaphore: Semaphore) {
  def runBlocking[T](action: => Future[T]): Future[T] = {
    semaphore.acquire()
    val started = try {
      action
    }
    catch {
      case NonFatal(th) => {
        semaphore.release()
        throw th
      }
    }

    started.andThen {
      case _ => semaphore.release()
    }(ExecutionContext.Implicits.global)
  }
}

val rateLimiter = new RateLimiter(new Semaphore(20))
val tasks = (1 to 100)
val futures: Seq[Future[Int]] = tasks.map(i => rateLimiter.runBlocking(Future{
    i * 2
  }(ExecutionContext.Implicits.global)))
futures.foreach(f => Await.result(f, Duration.Inf))
它不是完美的,因为它在两个位置阻塞(在信号量和“等待”中),并在内存中保存所有未来(可以避免)


但它可以在生产环境中使用:)

下面是一个简单的例子,它使用Akka Streams为您的用例建模

让我们将处理定义为一个方法,该方法接受
字符串
,并返回
未来[String]

def process(id: String): Future[String] = ???
然后,我们从一个包含500000个
字符串
元素的
列表创建一个
,并使用它将元素提供给处理方法。并行级别设置为20,这意味着在任何时间点运行的
Future
s不超过20。随着每个
未来的
完成,我们将执行附加处理并打印结果:

Source((1 to 500000).map(_.toString).toList)
  .mapAsync(parallelism = 20)(process)
  // do something with the result of the Future; here we create a new string
  //   that begins with "Processed: "
  .map(s => s"Processed: $s")
  .runForeach(println)

您可以在中阅读有关
mapsync
的更多信息。

使用Monix非常容易。akka streams非常适合您的场景,如果您已经对Scala有点熟悉(它还有一个JavaDSL),那么您很快就会了解它的DSL。Akka streams有内置的背压设施,应该注意不要淹没下游队列,但是如果您想要更细粒度地控制处理数据的速率,它也有节流设施-我应该记录更多关于信号量的信息,在某些情况下,它可能很有用。如果元素的下游顺序不重要,您可以使用
mapAsyncUnordered
mapAsync
对我来说是一个拦截器。