【问题标题】:Converting Scala @suspendable Method into a Future将 Scala @suspendable 方法转换为 Future
【发布时间】:2011-11-09 18:58:13
【问题描述】:

假设我有一个睡眠功能:

def sleep(delay:Int) : Unit @suspendable = {
  ....
}

是否有可能有一个函数 future 来创建可以同步等待的 sleep 函数的异步版本。

def future(targetFunc: (Int => Unit @suspendable)) : (Int => Future) = {
    ....
}

class Future {
  def await : Unit @suspendable = {
     ....
  }
}

你应该可以这样做:

reset {
  val sleepAsync = future(sleep)
  val future1 = sleepAsync(2000)
  val future2 = sleepAsync(3000)
  future1.await
  future2.await
  /* finishes after a delay of 3000 */
}

对 sleepAsync 的两次调用应该会立即返回,对 Future#await 的两次调用应该会出现阻塞。当然,它们都真正脱离了重置的结束,并且之后的代码负责在延迟后调用延续。

否则是否有替代方法可以并行运行两个@suspendable 函数并等待它们完成?

我有一个可编译的要点,其中包含我想做的事情的骨架:https://gist.github.com/1191381

【问题讨论】:

标签: scala continuations


【解决方案1】:
object Forks {

  import scala.util.continuations._

  case class Forker(forks: Vector[() => Unit @suspendable]) {
    def ~(block: => Unit @suspendable): Forker = Forker(forks :+ (() => block))
    def joinIf(pred: Int => Boolean): Unit @suspendable = shift { k: (Unit => Unit) =>
      val counter = new java.util.concurrent.atomic.AtomicInteger(forks.size)
      forks foreach { f =>
        reset {
          f()
          if (pred(counter.decrementAndGet)) k()
        }
      }
    }
    def joinAll() = joinIf(_ == 0)
    def joinAny() = joinIf(_ == forks.size - 1)
  }

  def fork(block: => Unit @suspendable): Forker = Forker(Vector(() => block))
}

使用 fork(),我们现在可以等待许多“suspendables”。使用 ~() 将suspendables链接在一起。使用 joinAll() 等待所有可挂起,而 joinAny() 只等待一个。使用 joinIf() 自定义连接策略。

object Tests extends App {

  import java.util.{Timer, TimerTask}
  import scala.util.continuations._

  implicit val timer = new Timer

  def sleep(ms: Int)(implicit timer: Timer): Unit @suspendable = {
    shift { k: (Unit => Unit) =>
      timer.schedule(new TimerTask {
        def run = k()
      }, ms)
    }
  }

  import Forks._

  reset {
    fork {
      println("sleeping for 2000 ms")
      sleep(2000)
      println("slept for 2000 ms")
    } ~ {
      println("sleeping for 4000 ms")
      sleep(4000)
      println("slept for 4000 ms")
    } joinAll()
    println("and we are done")
  }
  println("outside reset")
  readLine
  timer.cancel
}

这是输出。程序在时间 T 开始:

sleeping for 2000 ms
sleeping for 4000 ms
outside reset         <<<<<< T + 0 second
slept for 2000 ms     <<<<<< T + 2 seconds
slept for 4000 ms     <<<<<< T + 4 seconds
and we are done       <<<<<< T + 4 seconds

【讨论】:

    【解决方案2】:

    我不确定我是否完全理解了这个问题,但这里是一个尝试:

    import scala.util.continuations._
    
    class Future(thread: Thread) {
      def await = thread.join
    }
    
    object Future {
    
      def sleep(delay: Long) = Thread.sleep(delay)
    
      def future[A,B](f: A => B) = (a: A) => shift { k: (Future => Unit) =>
        val thread = new Thread { override def run() { f(a) } }
        thread.start()
    
        k(new Future(thread))
      }
    
      def main(args:Array[String]) = reset {
        val sleepAsync = future(sleep)
        val future1 = sleepAsync(2000) // returns right away
        val future2 = sleepAsync(3000) // returns right away
        future1.await // returns after two seconds
        future2.await // returns after an additional one second
        // finished after a total delay of three seconds
      }
    }
    

    这里,Future 实例只不过是Thread 上的句柄,因此您可以使用它的join 方法阻塞直到它完成。

    future 函数接受A =&gt; B 类型的函数,并返回一个函数,当提供A 时,该函数将启动一个线程以运行“未来”函数,并将其包装在@ 987654328@,将其注入回延续,从而将其分配给val future1

    这是否与您的目标相近?

    【讨论】:

    • 你可以随心所欲地运行延续,但不知何故,它们需要从当前线程中运行(否则总运行时间将是 5000 毫秒而不是 3000 毫秒)。在实践中,您可能会使用线程池而不是创建自己的 Thread 实例。你想如何运行future1future2
    • 啊。我希望未来能够采用可暂停功能而不是普通功能
    • 我现在自己都搞糊涂了。为什么future 的目的不是采用不可暂停的函数并创建一个延续,以便在继续其余代码的同时暂停该函数?
    • 我认为这样你就可以并行运行而不是顺序运行。例如,如果您有:resp1 = http.get "http://foo"; resp2 = http.get "http://bar" 它们当前正在按顺序运行,但您可能不需要它们按顺序运行,而是希望它们并行运行,所以您会这样做 resp1Future = http.get "http://foo"; resp2Future = http.get "http://bar"; resp1 = resp1Future.get; resp2 = resp2Future.get
    猜你喜欢
    • 2015-07-30
    • 2016-05-04
    • 2019-10-25
    • 1970-01-01
    • 2019-09-01
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多