【问题标题】:Vala yield not returningVala 产量未返回
【发布时间】:2020-12-26 03:51:08
【问题描述】:

我在 Vala 中编写异步函数时遇到问题。
我知道函数的回调必须在某处注册才能在 yield 语句之后继续执行,所以我将它添加到 GLib 主循环中,以便使用Idle.add 定期调用。这是我的虚拟代码:

async void loop_func()
{
    var id = Idle.add(loop_func.callback);
    message("Added idle %u",id);

    yield;
    message("yielded successfully 1");

    yield;
    message("yielded successfully 2");

    for (var i = 0; i < 20; i++)
    {
        message("%d",i);
        yield;
    }

    message("finished");
}

int main()
{
    var loop = new GLib.MainLoop();
    loop_func.begin(() => {loop.quit();});
    loop.run();
    return 0;
}

尽管如此,第二条 yield 语句之后的代码永远不会被执行。 这可以从输出中看出:

$ ./async   
** Message: 20:07:24.932: async.vala:4: Added idle 1
** Message: 20:07:24.932: async.vala:7: yielded successfully 1

然后它挂起。
我在这里错过了什么?

【问题讨论】:

  • 我不清楚当异步函数有多个 yield; 语句时应该发生什么。您是否从某个可能提供更多上下文的地方获得了这个示例?
  • 我想在 for 循环中执行一些昂贵的操作,但在每次迭代后将控制权交还给 CPU 以阻止线程挂起。每次在循环迭代后产生时,只要 CPU 再次空闲,我都希望从那里继续执行。我现在找到了这样做的方法;感谢您的帮助!
  • yield 的目的是安排一个异步回调,所以当耗时的操作在一个单独的函数中完成然后流程返回到 yield,GIO 有很多异步函数,例如yield file.mount_mountable (MountMountFlags.NONE);
  • 是的,有很多带有多个 yield some_other_async_function(); 的异步函数示例,但我找不到带有多个 yield; 的异步函数。

标签: asynchronous gtk yield glib vala


【解决方案1】:

虽然 GLib 反复调用空闲函数直到它告诉它停止(通过返回 false),但异步函数的 .callback 似乎在被调用后立即退出重复。

这可以通过每次在 yield 语句之前再次添加回调来克服:

async void loop_func()
{
    for (var i = 0; i < 20; i++)
    {
        Idle.add(loop_func.callback);
        yield;
    }
}

另一种(可能更有效)的方法是忽略异步函数的回调返回的值:

async void loop_func()
{
    var id = Idle.add(() => {loop_func.callback(); return Source.CONTINUE;});

    for (var i = 0; i < 20; i++)
    {
        yield;
    }

    Source.remove(id);
}

【讨论】:

  • MainLoop 是对GMainContext 的抽象,GMainContext 是 GLib 的事件循环,可以按线程或更多线程创建,允许多个事件循环,如果您尝试将流控制添加到耗时操作,但想维护一个单独的响应线程,例如对于用户输入,然后可以看看developer.gnome.org/gnome-devel-demos/stable/…以获得灵感
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 2018-03-29
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多