有人可以解释 async 方法与Vala中创建线程之间的区别吗?我应该在我的代码中使用哪一个?
答案 0 :(得分:10)
线程可以独立调度,而async
方法在主线程中运行,也就是说,它们是协同程序。例如,如果您阻止在单独的线程中读取套接字,则应用程序可以继续运行,但如果您使用async
方法执行此操作,则应用程序将阻止。
线程和协同程序(async
方法)可以解决一些相同的问题,但通常会做不同的事情。在Gtk +(和许多其他GUI系统)中,只有一个线程可以操作GUI对象,而GUI对象中的事件只会发生在这个线程中(通常称为事件调度线程)。如果另一个线程想要访问GUI项,则需要a)经历一些锁定过程或b)向EDT发送消息。这推广到所有线程间通信:在线程之间进行通信或使用共享资源,需要锁定和通信。
协同程序在EDT中被执行为“另一个事件”。考虑一种情况,你有一个带有下载按钮的窗口。当用户单击该按钮时,EDT将启动与该按钮关联的单击处理程序。如果该代码实际上是试图下载该文件,则GUI将冻结,直到文件完成下载。如果一个协程已经启动,那么按钮的处理程序将启动一个async
方法,该方法将打开一个套接字然后被告知它还没有准备好。然后它将套接字和回调放入EDT的循环(GLib.MainLoop
)。按钮的处理程序将完成,EDT将等待来自X显示器或套接字的事件,然后调用正确的回调来处理它。这允许使用套接字事件以交错方式处理GUI事件。但是,一次只能处理一个处理程序,因此处理程序需要能够快速完成,否则应用程序将无法响应。
使用协同程序变成了一大堆回调,但async
方法隐藏了回调,因此它看起来像直线代码,即使它不是。
如果您的任务主要是等待,那么协同程序是正确的选择。如果你的任务正忙着工作,那么毫无疑问需要进入一个线程。 Courotines不能超过一个CPU的工作,而线程可以在多个CPU上并行运行。 GLib的协同程序也不容易与线程混合:尝试让async
方法在两个线程中独立运行是不合理的:只有EDT才能使用async
方法。