Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何更新GTK+;Vala中的UI来自一个长操作而不阻塞UI_Multithreading_Gtk3_Vala - Fatal编程技术网

Multithreading 如何更新GTK+;Vala中的UI来自一个长操作而不阻塞UI

Multithreading 如何更新GTK+;Vala中的UI来自一个长操作而不阻塞UI,multithreading,gtk3,vala,Multithreading,Gtk3,Vala,当我在不修改任何内容的情况下使用此页面中的任何代码时: 我总是得到: 警告:不推荐使用“g\U简单\U异步\U结果\U新建”:请改用“g\U任务\U新建”。 因此,我继续建议使用。然而,当我尝试在Vala中使用GLib.Task时,我只需要声明一个任务就被卡住了。因此,我没有在自己的代码中使用来自GIO的async,因为它已被弃用,我尝试使用GLib.Task简单地用for循环中的数字更新Gtk按钮的标签,这样代码如下所示: using Gtk; Button button; public s

当我在不修改任何内容的情况下使用此页面中的任何代码时:

我总是得到:
警告:不推荐使用“g\U简单\U异步\U结果\U新建”:请改用“g\U任务\U新建”。

因此,我继续建议使用。然而,当我尝试在Vala中使用GLib.Task时,我只需要声明一个任务就被卡住了。因此,我没有在自己的代码中使用来自GIO的async,因为它已被弃用,我尝试使用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();
    }
}
使用Gtk;
按钮;
公共静态int main(字符串[]args){
Gtk.init(参考参数);
var窗口=新窗口();
window.title=“在不阻塞UI的情况下计数”;
window.border_width=10;
window.window\u position=WindowPosition.CENTER;
window.set_默认_大小(350,70);
window.destroy.connect(Gtk.main_退出);
按钮=新按钮,带有_标签(“开始计数”);
button.clicked.connect(()=>{
GLib.Task Task=新建GLib.Task(按钮,new cancelable());
});
window.add(按钮);
window.show_all();
Gtk.main();
返回0;
}
无效计数(){
对于(int i=0;i<10000;i++){
button.label=i.到_字符串();
}
}
但在编译时,我得到:
error:“\u data\u”未声明(此函数首次使用)
_tmp3=g任务新任务完成(\u数据->恢复)

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

我发现的主要问题是Vala中的GTask构造函数签名与C不同。因此,我无法重新创建此处的代码:

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

因此,我的问题是:

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

谢谢


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

使用async是完全可以的,并且可以将当前代码移植到使用GTask

您的计数代码是阻塞的,因此即使它的执行由GTask缓冲,它仍然会阻塞UI

执行CPU密集型后台操作的正确方法要么异步使用子流程,要么在线程中启动工作并在主循环中分派

async void test_async () {
    new Thread<void> (() => {
         // count here...
        test_async.callback ();
    });
    yield;
}
下面是一个完整且有效的示例:

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;
    }
}
使用Gtk;
按钮;
公共静态int main(字符串[]args){
Gtk.init(参考参数);
var窗口=新窗口();
window.title=“在不阻塞UI的情况下计数”;
window.border_width=10;
window.window\u position=WindowPosition.CENTER;
window.set_默认_大小(350,70);
window.destroy.connect(Gtk.main_退出);
按钮=新按钮,带有_标签(“开始计数”);
button.clicked.connect(()=>{
计数();
});
window.add(按钮);
window.show_all();
Gtk.main();
返回0;
}
异步无效计数(){
对于(int i=0;i<10000;i++){
button.label=i.到_字符串();
Idle.add(count.callback);
产量
}
}

使用async是完全正确的,并且有一个方法可以将当前代码移植到使用GTask

您的计数代码是阻塞的,因此即使它的执行由GTask缓冲,它仍然会阻塞UI

执行CPU密集型后台操作的正确方法要么异步使用子流程,要么在线程中启动工作并在主循环中分派

async void test_async () {
    new Thread<void> (() => {
         // count here...
        test_async.callback ();
    });
    yield;
}
下面是一个完整且有效的示例:

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;
    }
}
使用Gtk;
按钮;
公共静态int main(字符串[]args){
Gtk.init(参考参数);
var窗口=新窗口();
window.title=“在不阻塞UI的情况下计数”;
window.border_width=10;
window.window\u position=WindowPosition.CENTER;
window.set_默认_大小(350,70);
window.destroy.connect(Gtk.main_退出);
按钮=新按钮,带有_标签(“开始计数”);
button.clicked.connect(()=>{
计数();
});
window.add(按钮);
window.show_all();
Gtk.main();
返回0;
}
异步无效计数(){
对于(int i=0;i<10000;i++){
button.label=i.到_字符串();
Idle.add(count.callback);
产量
}
}

请参见此处的讨论:尽快更新UI几乎肯定会在单线程模型中阻止它。你可以进行更重要的计算,或者在我的答案中循环使用
GLib.Timeout
。我不太确定我是否了解那里发生了什么以及该补丁的效果。我有一个更新版本的glib:2.48.1,不管在代码中使用--target glib=2.48.1和valac,我仍然会得到一个警告。我认为临时解决方案不起作用。请看这里的讨论:尽快更新UI几乎肯定会在单线程模型中阻止它。你可以进行更重要的计算,或者在我的答案中循环使用
GLib.Timeout
。我不太确定我是否了解那里发生了什么以及该补丁的效果。我有一个更新版本的glib:2.48.1,不管在代码中使用--target glib=2.48.1和valac,我仍然会得到一个警告。我认为暂时的解决办法行不通。谢谢。我将其标记为解决方案,但仍然收到相同的警告。而且,编译器说,第一次代码截取不允许在那里使用lambda表达式。第二个需要稍微修理一下。它应该是:“异步vo”