如何在当前线程中运行ScalaZ Task

时间:2016-11-01 01:48:29

标签: scala concurrency task scalaz

应该很简单,但我不知道该怎么做。我想在当前线程中运行ScalaZ Task。我很惊讶task.run没有在当前线程上运行,因为它是同步的。

是否可以在当前线程上运行它,以及如何操作?

2 个答案:

答案 0 :(得分:0)

http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/以来有一些更新和弃用。

现在推荐的同步调用任务的方法是:

class Timed
{
//...
}

void foo()
{
    Timed t_;

    //Do the rest of work
}

但请记住,它并不完全在调用者的线程中完成 - 执行是在为任务定义的线程池中执行的,但调用者的线程阻塞直到执行是完了。没有办法让任务在同一个线程中完全运行。

答案 1 :(得分:0)

一般情况下,如果使用Task.async,则无法使复合Task始终保持在同一个线程中,因为cb(回调)可以从任何地方调用(任何地方)线程),所以在链中像:

 Task
   .delay("aaa")
   .map(_ + "bbb")
   .flatMap(x => Task.async(cb => completeCallBackSomewhereElse(cb, x)))
   .map(_ + "ccc")
   .unsafePerformSync

_ + "bbb"将在来电者的线程中执行

_ + "ccc"将在Somewhereelse的帖子中执行,因为scalaz无法控制它。

基本上,这允许Task成为异步操作的强大工具,因此它甚至可能不知道底层线程池,甚至在没有纯线程和wait / notify的情况下实现行为。

但是,在某些特殊情况下,它可能会作为调用者运行:

1)没有Strategy / Task.async相关内容:

Task.delay("aaa").map(_ + "bbb").unsafePerformSync

unsafePerformSync使用CountDownLatch等待runAsync的结果,因此如果路上没有异步/非确定性操作,runAsync将使用{{3} }}:

  /** 
   * Run this `Future`, passing the result to the given callback once available. 
   * Any pure, non-asynchronous computation at the head of this `Future` will
   * be forced in the calling thread. At the first `Async` encountered, control
   * switches to whatever thread backs the `Async` and this function returns.
   */
  def runAsync(cb: A => Unit): Unit = 
    listen(a => Trampoline.done(cb(a)))

2)您可以控制执行策略。所以caller's thread会有所帮助。此外,它已经在scalaz中实现并称为Strategy.sequential

P.S。

1)如果您只是想尽快开始计算,请使用task.now / Task.unsafeStart

2)如果你想要一些与异步内容不太相关但仍然懒惰和堆栈安全的东西,你可以看看这里(它是Cats库的)this simple Java trick

3)如果您只需要封装副作用 - 请查看http://eed3si9n.com/herding-cats/Eval.html