我有一个专用的类,其中包括一个BackgroundWorker,它负责从队列中运行特定于类的操作-需要使用COM对象的操作。
当应用程序启动时,在运行时从UI线程创建专用类的对象(WPF)。当类的构造函数被调用时,它实例化一个BackgroundWorker,该a运行从UI线程分配的异步出队操作。
但是,当这些操作需要从COM对象产生的数据时,我注意到UI线程在响应用户输入之前等待BackgroundWorker完成操作。
如何隔离以使UI线程不受COM函数的影响,这些函数最多需要10秒才能完成?
代码:
public class User(){
private BackgroundWorker Worker;
private Queue<Action> ActionQueue;
private COM COMObject; // COM is an interface exposed by the COM referenced in VS project
private bool Registered;
public User(){
this.Registered = true;
this.ActionQueue = new Queue<Action>();
this.Worker = new BackgroundWorker();
this.Worker.DoWork += new DoWorkEventHandler(DoWork);
this.Worker.DoWork += new RunWorkerCompletedEventHandler(WorkerCompleted);
this.Worker.Worker.WorkerSupportsCancellation = true;
this.Worker.Worker.RunWorkerAsync();
this.COMObject = new COM();
}
private DoWork(object sender, DoWorkEventArgs e){
// If there is something to be done (an action) in the queue
if (ActionQueue.Count > 0){
// Dequeue the action from the queue
Action queuedAction = ActionQueue.Dequeue();
// Do the action
queuedAction();
}
}
private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
// While this machine continues to be registered to the app...
if (this.Registered)
{
Worker.RunWorkerAsync();
}
}
public void ConnectToDatabase(){
Action action = delegate {
COMObject.Connect(); // function can take up to 10 seconds to return
}; // end of action delegate
ActionQueue.Enqueue(action);
}
}使用代码(在UI线程中):
User user = new User();
user.ConnectToDatabase();在我的UI中,在应用程序启动期间,最多可以创建并调用10个User对象进行连接。如果我注释掉User::ConnectToDatabase中的COMObject.Connect();行并将其替换为Thread.Sleep(10000),则UI线程不会等待10+秒。但是,就像现在的代码一样,我注意到在再次处理WPF应用程序中的任何用户输入之前,COMObject.Connect();行确实会导致10+秒。
如何隔离以便与COM对象相关的函数不会影响UI线程的性能?
(注意:与BackgroundWorker一起排队的操作与UI线程没有交互。在这些操作中只更改类特定的属性)。
发布于 2020-08-07 04:10:41
答案总是隐藏在评论中:)
正如@Blindy和@jdweng指出的,new COM()是在主UI线程上调用的,而COM对象的所有功能都是在不同的线程上使用的。
此外,我确实使用STAThread属性(this.Worker.SetApartmentState(ApartmentState.STA);)设置了COM对象的线程。
而且,我确实从使用BackgroundWorker改为使用实际的线程。
最后,但并非最不重要的一点是,当@Blindy指出使用Queue<Action>在工作线程(从主UI线程排队)上执行工作时存在的问题时,根据@Anders H的建议,我最终确实使用了ConcurrentQueue<Action>。我会使用Tasks,从我在该主题上所做的大量研究来看,Tasks本可以解决跨线程访问的潜在问题,但是,由于排队的“工作”必须按顺序进行并且与COM对象相关,因此ConcurrentQueue暂时看起来是一个不错的解决方案。但是,稍后将不得不重新考虑这一点。
https://stackoverflow.com/questions/62644741
复制相似问题