首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Task#apply对Task#delay

Task#apply对Task#delay
EN

Stack Overflow用户
提问于 2017-03-11 19:54:34
回答 1查看 497关注 0票数 1

给定以下通过scala.concurrent.Task创建的Task#delay实例

代码语言:javascript
复制
val t = 
   Task.delay { println(Thread.currentThread); Thread.sleep(5000); 42 }

我编写了一个将异步运行t的方法。

代码语言:javascript
复制
def f = t.runAsync { 
      case \/-(x) => println(x)
      case -\/(e) => println(e.getMessage) 
}

运行它显示f完全计算,即等待5秒,然后再计算。换句话说,第二个f似乎要等到第一个f完成。

代码语言:javascript
复制
scala> {f; f; }
Thread[run-main-0,5,run-main-group-0]
42
Thread[run-main-0,5,run-main-group-0]
42

然后,我用t重写了Task#apply

代码语言:javascript
复制
val u = 
  Task { println(Thread.currentThread); Thread.sleep(5000); 42 }

再次,我定义了一个使用u执行runAsync的方法。

代码语言:javascript
复制
def g = u.runAsync { 
     case \/-(x) => println(x)
     case -\/(e) => println(e.getMessage) 
}

最后,我运行了两个g's。

代码语言:javascript
复制
scala> {g; g}
Thread[pool-3-thread-2,5,run-main-group-0]
Thread[pool-3-thread-3,5,run-main-group-0]

scala> 42
42

然而,在上述结果中,g或多或少是同时运行的。

我原以为{f; f; }会异步运行,即以与g相同的方式运行。但是,在我看来,打电话给f造成了麻烦。

编辑

任务runAsync上的文档记录

任何纯的、非异步的计算都将在调用线程中强制执行。

由于t的主体是非异步的,我想上面的注释解释了为什么它会阻塞,即“在调用线程中强制执行”。

什么时候是使用Task#delayTask#apply的合适时机?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-11 21:01:17

您可以将Task.delay视为类似于() => Try[A]的高级版本。它暂停计算的计算,但对于评估最终将在哪个线程上运行没有什么好说的(这意味着它只是在当前线程上运行)。

这往往正是你想要的。考虑一下这样的定义:

代码语言:javascript
复制
val currentTime: Task[Long] = Task.xxx(System.currentTimeMillis)

我们不能使用now,因为这将立即评估时间(并且只在定义上只计算一次)。我们可以使用apply,但是强制这个计算的异步边界是浪费和不必要的-我们实际上希望它在当前线程中运行,而不是现在。这正是delay所提供的。

通常,当您对计算建模时,如果某些东西总是计算成本很高,您可能需要考虑Task.apply,这意味着计算总是在由当前隐式ExecutorService确定的线程上进行。这可能会使使用变得更干净,而以牺牲灵活性为代价--您正在将您所知道的有关计算计算的运行时特性的内容写入其定义中。

使用delay来定义异步计算的好处是,始终可以通过用Task.fork包装Task来强制异步边界,这在本质上和用Task.apply定义计算时得到的一样。不可能朝相反的方向发展--如果使用Task.apply,隐式策略将确定计算的计算位置,这就是它的全部内容。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42739896

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档