当在UI线程上进行大量CPU密集型工作时,如何在C#VSTO addin中保持Outlook UI的响应性

当在UI线程上进行大量CPU密集型工作时,如何在C#VSTO addin中保持Outlook UI的响应性,c#,outlook,async-await,vsto,C#,Outlook,Async Await,Vsto,我有一段代码,它在一个循环中多次调用outlookapi。Outlook不喜欢从工作线程访问其API,所以我必须使用主线程。使用async/await进行网络查询的代码部分非常好,因此UI不会冻结。但当代码达到CPU密集型部分(调用Outlook API)时,UI显然会冻结 我插入了wait Task.Delay(1),它在每10毫秒后执行一次,但由于计时器分辨率不太精确(15毫秒),它使代码明显变慢(尽管解锁了UI) 使用Task.Yield而不是Task.Delay(1)不会解除对UI的阻止

我有一段代码,它在一个循环中多次调用outlookapi。Outlook不喜欢从工作线程访问其API,所以我必须使用主线程。使用async/await进行网络查询的代码部分非常好,因此UI不会冻结。但当代码达到CPU密集型部分(调用Outlook API)时,UI显然会冻结

我插入了
wait Task.Delay(1)
,它在每10毫秒后执行一次,但由于计时器分辨率不太精确(15毫秒),它使代码明显变慢(尽管解锁了UI)

使用
Task.Yield
而不是
Task.Delay(1)
不会解除对UI的阻止(MSDN无论如何都不建议使用Task.Yield)

interval
从10ms增加到更大的值(100ms)可以将性能损失降至最低,并使UI具有一定的响应性,但不太平滑


也许有更好的替代方案,不意味着在UI平滑度和性能之间进行任何权衡?可能像一个很好的老
应用程序。DoEvents
,但以一种现代的推荐方式?

单独使用OOM并没有好的方法。扩展的MAPI是线程安全的,但它只能从C++或Delphi访问。您可以使用(任何语言)-它的对象族完全基于MAPI,并且可以从辅助线程使用。将
Application.Session.MAPIOBJECT
保存到主线程上的一个专用变量中(这样,只需封送该变量)。在次线程上,创建对象的实例(这样MAPI系统将在该线程上初始化),并将其MAPIOBJECT属性设置为保存在主线程上的variabel。这样,两者将共享相同的MAPI会话。然后,您可以使用
RDOSession.GetFolderFromID
/
GetDefaultFolder
/等检索文件夹,并处理项目

单独使用OOM没有什么好办法。扩展的MAPI是线程安全的,但它只能从C++或Delphi访问。您可以使用(任何语言)-它的对象族完全基于MAPI,并且可以从辅助线程使用。将
Application.Session.MAPIOBJECT
保存到主线程上的一个专用变量中(这样,只需封送该变量)。在次线程上,创建对象的实例(这样MAPI系统将在该线程上初始化),并将其MAPIOBJECT属性设置为保存在主线程上的variabel。这样,两者将共享相同的MAPI会话。然后,您可以使用
RDOSession.GetFolderFromID
/
GetDefaultFolder
/等检索文件夹,并处理项目

您可能知道,OOM不能从辅助线程使用,或者代码中可能会出现异常。Outlook的最新版本
检测此类用例并可能引发异常。但您可以自由使用Outlook基于的低级API—扩展MAPI或该API周围的任何其他包装器,如Redemption


<>注意,如果您只处理Exchange配置文件,可以考虑使用EWS或Outlook API来获取辅助线程上的所需数据。有关更多信息,请参阅

您可能知道,OOM不能从辅助线程使用,或者代码中可能会出现异常。Outlook的最新版本
检测此类用例并可能引发异常。但您可以自由使用Outlook基于的低级API—扩展MAPI或该API周围的任何其他包装器,如Redemption


<>注意,如果您只处理Exchange配置文件,可以考虑使用EWS或Outlook API来获取辅助线程上的所需数据。有关更多信息,请参阅

是的,我知道根本不使用OOM可以消除问题,但这不是我的选择。是的,我知道根本不使用OOM可以消除问题,但这不是我的选择。是的,我知道使用EMAPI或EWS的可能性。但我的问题更加“狭隘”和具体。它是关于在主线程中处理UI事件的,而不是关于OOM的替代方案(这将是一个不同且非常重要的故事)。我相信在这种情况下,用户会陷入延迟和UI冻结的陷阱。为什么拒绝扩展MAPI?这正是Outlook开发人员应该使用的情况。理论上,是的。但是在实践中,重写整个应用程序以使用Ext.MAPI将是太多的工作。我只是没有足够的资源。是的,我知道使用EMAPI或EWS的可能性。但我的问题更加“狭隘”和具体。它是关于在主线程中处理UI事件的,而不是关于OOM的替代方案(这将是一个不同且非常重要的故事)。我相信在这种情况下,用户会陷入延迟和UI冻结的陷阱。为什么拒绝扩展MAPI?这正是Outlook开发人员应该使用的情况。理论上,是的。但是在实践中,重写整个应用程序以使用Ext.MAPI将是太多的工作。我只是没有足够的资源。
DateTime d1 = DateTime.Now;
int interval = 10;
foreach (SomeItem item in items)
{
    // Intense access to Outlook API...
    // ...

    DateTime d2 = DateTime.Now;
    if (d2.Subtract(d1).TotalMilliseconds > interval)
    {
        await Task.Delay(1);
        d1 = d2;
    }
}