飞镖中的异步编程

Mit*_*ten 4 asynchronous dart

我关于如何做线程/异步的java.我使用新的Thread(target).start(),其中target是Runnable,作为在java中进行线程化的一种方法.新的并发api有其他选择但我们知道在特定的调用中新的线程正在创建并传递任务被执行.

同样在Dart中如何完成异步?我读了发送/接收,完成/未来,spawnFunction.对我来说,只有spawnFunction是令人信服的声明,它将创建新的线程.可以解释完成/未来的帮助.我知道他们采取回调但是在javascript/dart中有一些隐含的逻辑/规则,回调总是在不同的线程中执行.

下面是dart片段/伪代码:

void callback() {
  print("callback called");
}

costlyQuery(sql, void f()) {
  executeSql(sql);
  f();
}

costlyQuery("select * from dual", callback);
Run Code Online (Sandbox Code Playgroud)

我希望我的昂贵的Query签名作为第二个参数的功能是正确的.所以现在我不认为f()以后executeSql(sql)会异步.可能正在采取以上示例添加完成者/未来如果可以使异步帮助我理解.

bea*_*mit 9

tl; dr:没有隐含的规则,回调不会阻止.

Javascript事件队列

在Javascript中,没有线程(除了WebWorkers,但这是不同的).这意味着如果代码的任何部分阻塞,整个应用程序将被阻止.回调没有什么神奇之处,它们只是函数:

function longLoop(cb) {
    var i = 1000000;
    while (i--) ;
    cb();
}

function callback() {
    console.log("Hello world");
}

function fun() {
    longLoop(callback);
    console.log("Called after Hello World is printed");
}
Run Code Online (Sandbox Code Playgroud)

要使异步生成,必须将回调放在事件队列中,这只发生在一些API调用中:

  • 用户启动的事件处理程序 - 点击,键盘,鼠标
  • API事件处理程序 - XmlHTTPRequest回调,WebWorker通信
  • 计时函数--setTimeout,setInterval

触发事件时,回调将放在事件队列上,以便在所有其他回调执行完毕后执行.这意味着您的代码中不会同时执行两行代码.

期货

我假设你至少偶然发现了这篇关于期货的帖子.如果没有,这是一个很好的阅读,直接来自马口.

在Javascript中,您必须做一些工作才能理解异步代码.甚至还有一个名为future的Javascript库用于执行常见操作,例如异步循环和序列(完全公开,我亲自与该库的作者合作).

未来的概念是创造未来的功能所做出的承诺,未来将在未来的某个时刻完成.如果要进行异步调用,请创建未来,返回它,并在异步调用完成时履行承诺.来自博文:

Future<Results> costlyQuery() {
    var completer = new Completer();

    database.query("SELECT * FROM giant_table", (results) {
        // when complete
        completer.complete(results);
    });

    // this returns essentially immediately,
    // before query is finished
    return completer.future; 
}
Run Code Online (Sandbox Code Playgroud)

如果database.query是阻塞调用,则将立即完成将来的操作.此示例假定这database.query是一个非阻塞调用(异步),因此将在此函数退出后继续执行.completer.completecompleter.then()使用指定的参数调用传递给的任何函数.

您的示例,修改为惯用和异步:

void callback() {
  print("callback called");
}

costlyQuery(sql) {
  var completer = new Completer();
  executeSql(sql, () => completer.complete());
  return completer.future;
}

costlyQuery("select * from dual").then(callback);
Run Code Online (Sandbox Code Playgroud)

这是异步的并正确使用期货.您可以将自己的回调函数传递给您costlyQuery,并在回调中调用它executeSql来实现相同的功能,但这是Javascript方式,而不是Dart方式.

分离

隔离类似于Java的线程,除了隔离是并发模型,线程是并行模型(有关并发与并行的更多信息,请参阅此SO问题).

Dart的特殊之处在于规范并未强制要求所有内容都在单个线程中运行.它只强制要求不同的执行上下文不能访问相同的数据.每个隔离区都有自己的内存,只能通过发送/接收端口与其他隔离区进行通信(例如发送数据).

如果您熟悉,这些端口与Go中的通道类似.

隔离是一个独立于其他代码运行的独立执行上下文.在Javascript术语中,这意味着它拥有自己的事件队列.有关隔离物的更完整介绍,请参阅Dart之旅.

让我们说你的executeSql是一个阻塞函数.如果我们不想等待它完成,我们可以将它加载到隔离中:

void callback() {
    print("callback called");
}

void costlyQuery() {
    port.receive((sql, reply) {
        executeSql(sql);
        reply.send();
    });
}

main() {
    var sendPort = spawnFunction(costlyQuery);

    // .call does all the magic needed to communicate both directions
    sendPort.call("select * from dual").then(callback);

    print("Called before executeSql finishes");
}
Run Code Online (Sandbox Code Playgroud)

此代码创建隔离,向其发送数据,然后在完成后注册回调.即使executeSql块,main()也不一定会阻塞.