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”