Vala编程语言高级特性-异步方法
异步方法
异步方法是一类可由程序员控制暂停与恢复执行的方法。它们常用于应用程序的主线程中,当某个方法需要等待外部耗时任务完成,但又必须确保其他处理不被阻塞时(例如,某个慢操作不应冻结整个图形界面)。当该方法需要等待时,它会将CPU控制权交还给其调用者(即yield),但同时会安排在数据就绪时被回调以恢复执行。异步方法可能等待的外部慢任务包括:等待远程服务器的数据、等待另一线程完成计算,或等待从磁盘驱动器加载数据。
异步方法通常需要在GLib主事件循环运行的环境下使用,因为空闲回调(idle callbacks)被用于处理部分内部回调。但在特定条件下,异步方法也可在不运行GLib主循环的情况下使用,例如当异步方法总是执行yield操作且从未使用Idle.add()时。
待办
补充异步方法无需GLib主循环可用的确切条件
异步方法的设计目标是在单一线程内交错处理多个不同的长期运行操作。它们本身并不将负载分散到不同线程上。然而,异步方法可用于控制后台线程并等待其完成,或将操作加入队列供后台线程处理。
Vala中的异步方法使用GIO库处理回调,因此编译时必须添加--pkg=gio-2.0
选项。
异步方法通过async关键字定义。例如:
async void display_jpeg(string fnam) {// 在后台线程加载JPEG并在加载完成后显示// [...]
}
或:
async int fetch_webpage(string url, out string text) throws IOError {// 异步获取网页,完成后返回HTTP状态码并将页面内容存入'text'// [...]text = result;return status;
}
该方法可像普通方法一样接受参数并返回值。它可在任意时刻使用yield语句将CPU控制权交还给调用者。
调用异步方法可采用以下两种形式之一:
display_jpeg.begin("test.jpg");
display_jpeg.begin("test.jpg", (obj, res) => {display_jpeg.end(res);
});
两种形式都会以给定参数启动异步方法。第二种形式额外注册了一个AsyncReadyCallback回调,该方法完成时会被执行。该回调接受源对象obj
和GAsyncResult实例res
作为参数。在回调中应调用.end()
方法以获取异步方法的返回值(若有)。若异步方法可能抛出异常,则.end()
调用处会接收到该异常且必须进行捕获。若方法包含out参数,则应在.begin()
调用中省略这些参数,并将其添加到.end()
调用中。
例如:
fetch_webpage.begin("http://www.example.com/", (obj, res) => {try {string text;var status = fetch_webpage.end(res, out text);// 调用结果存在于'text'和'status'中...} catch (IOError e) {// 错误处理...}
});
当异步方法开始运行时,它会持有CPU控制权直至遇到第一个yield语句,此时控制权返回给调用者。当该方法恢复执行时,它会从该yield语句之后立即继续执行。yield有几种常见用法:
此形式放弃控制权,但安排GLib主循环在无更多事件需要处理时恢复该方法:
Idle.add(fetch_webpage.callback);
yield;
此形式放弃控制权,并将回调细节存储起来供其他代码用于恢复该方法执行:
SourceFunc callback = fetch_webpage.callback;
/* … 将'callback'存储在某处 … */
yield;
此时其他地方的代码必须调用已存储的SourceFunc才能使该方法恢复执行。可通过调度GLib主循环来运行:
Idle.add((owned) callback);
若调用方运行在主线程中,也可直接调用:
callback();
若使用上述直接调用方式,被恢复的异步方法会立即获得CPU控制权,并运行至下一个yield语句后才会返回到执行callback()
的代码。若必须从后台线程进行回调(例如在某个后台处理完成后恢复异步方法),Idle.add()方法会非常有用。((owned)转换是为避免关于委托拷贝的警告所必需的。)
yield的第三种常见用法是调用另一个异步方法,例如:
yield display_jpeg(fnam);
或
var status = yield fetch_webpage(url, out text);
这两种情况下,调用方法都会放弃CPU控制权,直至被调方法完成后才会恢复。yield语句会自动向被调方法注册回调以确保调用方正确恢复。该自动回调还会收集被调方法的返回值。
当该yield语句执行时,CPU控制权首先传递给被调方法,该方法运行至其第一个yield语句后返回到调用方法,调用方法随后完成yield语句本身的执行,最后将控制权交还给其自身的调用者。