我需要一种机制来异步调用多个回调...所以我实现了以下类:
class AsyncCallbacks[T] {
private val callbacks = new ListBuffer[T => Future[Unit]]()
def +=(f: T => Future[Unit]) = callbacks += f
def -=(f: T => Future[Unit]) = callbacks -= f
def invoke(data: T) = Future.sequence(callbacks.map(_(data)))
}
...
def f1(i: Int) = Future { println(i) }
def f2(i: Int) = Future { println(i) }
val callbacks = new AsyncCallbacks[Int]
callbacks += f1
callbacks += f2
callbacks.invoke(5)
callbacks.invoke
生成scala.concurrent.Future[scala.collection.mutable.ListBuffer[Unit]]
...我想知道是否有一种更好,更有效的方法来调用所有已注册的回调,而不会生成Unit
s的无用列表
上面的实现还有另一个问题......让我们假设我们有以下方法......
def l1 = Future { List.fill(5)("1") }
def l2 = Future { List.fill(5)("2") }
...然后我像这样调用它们:
for {
a <- l1
b <- l2
c <- callbacks.invoke(5)
} yield b
callbacks.invoke
有效...但看起来它永远不会返回...
修改
好的,我已按照I.K.的建议尝试使用scalaz重新实现我的AsyncCallbacks
课程:
import scala.collection.mutable.ListBuffer
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz.concurrent.Task
class AsyncCallbacks[T] {
private val tasks = new ListBuffer[Task[T => Future[Unit]]]()
/** Gets the number of callbacks registered. */
def count = tasks.length
/** Clears all the registered callbacks. */
def clear = tasks.clear
/* Adds the specified function to the list of callbacks to be invoked. */
def +=(f: T => Future[Unit]) = tasks += Task(f)
/** Invokes all the registered callbacks. */
def invoke(data: T) = Future { Task.gatherUnordered(tasks).map(_.map(_(data))).run.length }
}
这是它的用法:
def f1(i: Int) = Future { println(i) }
def f2(i: Int) = Future { println(i) }
val callbacks = new AsyncCallbacks[Int]()
callbacks += f1
callbacks += f2
callbacks.invoke(4) // prints 4 two times (f1 + f2)
现在只需从REPL执行上面的代码...然后尝试多次调用`callbacks.invoke(4),你会发现你不再能够退出REPL(它仍然被阻止,你必须用CTRL-C退出。我认为这可能是真实应用中的一个问题。
答案 0 :(得分:1)
从您的帖子中可以看出,无论您想要将Future
的主体放入Task
的正文中,您希望它完成并通知您。
在Scalaz中,它将被建模为Future
,其下面基本上是scala> import scalaz.concurrent.Task
import scalaz.concurrent.Task
scala> val tasks = (1 |-> 5).map(n => Task { Thread.sleep(100); n })
tasks: List[scalaz.concurrent.Task[Int]] = List(scalaz.concurrent.Task@72b64eae, scalaz.concurrent.Task@3f6a6af, scalaz.concurrent.Task@5ba0314c, scalaz.concurrent.Task@36718c9f, scalaz.concurrent.Task@767277c1)
scala> Task.gatherUnordered(tasks).run
res10: List[Int] = List(4, 1, 2, 3, 5)
scala> Task.gatherUnordered(tasks).run
res11: List[Int] = List(3, 1, 2, 4, 5)
scala> Task.gatherUnordered(tasks).run
res12: List[Int] = List(2, 1, 3, 4, 5)
,但附带了其他功能。
一些例子,
Task
如您所见,每次完成这些任务的运行时,输出都是不同的。 scala> val tasks = List(Task{1},Task{2})
tasks: List[scalaz.concurrent.Task[Int]] = List(scalaz.concurrent.Task@2858b10a, scalaz.concurrent.Task@3782f5d8)
scala> Task.gatherUnordered(tasks).run
res13: List[Int] = List(1, 2)
scala> val tasks = List(Task{List.fill(5)("1")}, Task{List.fill(5)("2")})
tasks: List[scalaz.concurrent.Task[List[String]]] = List(scalaz.concurrent.Task@1c8dd945, scalaz.concurrent.Task@71f8e5ff)
scala> Task.gatherUnordered(tasks).run
res17: List[List[String]] = List(List(1, 1, 1, 1, 1), List(2, 2, 2, 2, 2))
实施是不确定的。
举个例子,
<div class = "row" id = "activityRow">
<select class="combobox" id = "activityCombobox" onclick="addButtons()">
<option value="" selected="true" style = "display:none;">-- Choose your Activity --</option>
<option value="val1" >Val1</option>
<option value="val2">Val2</option>
<option value="val3">Val3</option>
<option value="val4">Val4</option>
</select>
</div>
<div class="row" id = "addonRow">
</div>