gpt4 book ai didi

multithreading - 如何在不阻塞 UI 的情况下从长时间操作中更新 Vala 中的 GTK+ UI

转载 作者:行者123 更新时间:2023-12-03 13:17:06 24 4
gpt4 key购买 nike

当我使用此页面中的任何代码而不修改任何内容时:https://wiki.gnome.org/Projects/Vala/AsyncSamples

我总是得到:warning: ‘g_simple_async_result_new’ is deprecated: Use 'g_task_new' instead.
所以我继续使用 GTask 的建议。 .但是,当我尝试在 Vala 中使用 GLib.Task 时,我只是在声明一个任务时遇到了困难。因此,我没有在我自己的代码中使用来自 GIO 的异步,因为它已被弃用,我尝试使用 GLib.Task 来简单地使用 for 循环中的数字更新 Gtk 按钮的标签,这样代码如下所示:

using Gtk;
Button button;

public static int main (string[] args) {
Gtk.init (ref args);

var window = new Window ();
window.title = "Count without blocking the UI";
window.border_width = 10;
window.window_position = WindowPosition.CENTER;
window.set_default_size (350, 70);
window.destroy.connect (Gtk.main_quit);
button = new Button.with_label ("Start counting");
button.clicked.connect (() => {
GLib.Task task = new GLib.Task(button, new Cancellable());
});

window.add (button);
window.show_all ();

Gtk.main ();

return 0;
}

void count(){
for(int i = 0; i < 10000; i++){
button.label = i.to_string();
}
}

但是在编译时我得到: error: ‘_data_’ undeclared (first use in this function)
_tmp3_ = g_task_new_finish (_data_->_res_);

第 15 行是导致编译器抛出该错误的原因。它来自 vala 编译器生成的 C 代码。

我发现的主要问题是 Vala 中的 GTask 构造函数签名与 C 不同。因此,我无法重新创建此处找到的代码: GUI becomes unresponsive after clicking the button using GTK+ in C

因为对于初学者,我不允许将两个以上的参数传递给 GLib.Task 对象构造函数。 Task 对象的构造函数在每种语言中都不同。 Vala 中 GLib.Task 的构造函数可以找到 here .

因此我的问题是:

有没有关于如何在 Vala 中使用 GLib 任务(GTask)来执行更新 UI 而不阻塞它的操作的示例?如果没有,是否有另一种方法来更新 UI 而不会阻止它?一种不被弃用的方式?

谢谢。

P.S:我已经尝试过 GLib.Thread、GLib.ThreadPool 和 GLib.Idle。它们都在 for 循环中阻塞了 UI。 GLib.Idle 不会完全阻塞 UI,但它会呈现错误,因为在循环运行时响应用户输入变得非常慢。

最佳答案

使用 async 完全没问题,还有 some work already用于移植当前代码以使用 GTask。

你的计数代码是阻塞的,所以即使它的执行被 GTask 缓冲,它仍然会阻塞 UI。

执行 CPU 密集型后台操作的正确方法是异步使用子进程或在线程中启动工作并在主循环中分派(dispatch)。

async void test_async () {
new Thread<void> (() => {
// count here...
test_async.callback ();
});
yield;
}

GTask 或更一般的 GAsyncResult 只提供一个容器来保存异步操作的结果。他们还建议使用 GThreadPool,但它有点样板。

另一个有趣的事情是 test_async.callback实际上是一个 SourceFunc , 所以你可以在 GLib.Timeout 中传递它.

编辑:

为了更适合您的问题,如果您想在 UI 进行时更新 UI,请使用异步循环:
async test_callback () {
for (var i = 0; i < 10000; i++) {
button.label = i.to_string ();
Idle.add (test_async.callback);
yield; // pause execution until retriggered in idle
}
}

这是一个完整且有效的示例:
using Gtk;
Button button;

public static int main (string[] args) {
Gtk.init (ref args);

var window = new Window ();
window.title = "Count without blocking the UI";
window.border_width = 10;
window.window_position = WindowPosition.CENTER;
window.set_default_size (350, 70);
window.destroy.connect (Gtk.main_quit);
button = new Button.with_label ("Start counting");
button.clicked.connect (() => {
count ();
});

window.add (button);
window.show_all ();

Gtk.main ();

return 0;
}

async void count(){
for(int i = 0; i < 10000; i++){
button.label = i.to_string();
Idle.add (count.callback);
yield;
}
}

关于multithreading - 如何在不阻塞 UI 的情况下从长时间操作中更新 Vala 中的 GTK+ UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39502200/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com