c# - 使用 Excel 数据的简单任务未完成运行导致 "ContextSwitchDeadlock"

标签 c# excel com async-await com-interop

我有一个 Excel workbook 对象,其中包含一个 sheet,我想将其内容复制到 List.

我有这个方法:

private Task GeneratePagesList()
{                        
    _pages = new List<Model.Page>();                                                    
    short idCount = 0;

    var generatePagesListTask = new Task(() =>
        {                                                 
            _pages.Add(new Model.Page()
            {
                Url = new Uri(_worksheetRange.Cells[i, j].Value2.ToString(), 
                UriKind.RelativeOrAbsolute),
                Id = idCount
            });
        });
    return generatePagesListTask;
}

现在我想按如下方式使用此方法及其返回的 Task:

public async void ConvertExelDataAsync()
{                       
    var generatePagesListTask = GeneratePagesList();
    generatePagesListTask.Start();
    await generatePagesListTask;
}

当我运行时,操作花费的时间太长,而且它永远不会退出 ConvertExelDataAsync 方法,过了一会儿(显然是 60 秒),我收到一个Exception 上面写着:

Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in 'C:\Users\Aymen\Documents\Visual Studio 2013\Projects\WebGraphMaker\WebGraphMaker\bin\Debug\WebGraphMaker.vshost.exe'.

Additional information: The CLR has been unable to transition from COM context 0xd33a5e78 to COM context 0xd33a5fa0 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

注意:这是我第一次与 Com 对象交互。

更新 1:

不在任务中时,Excel消费正常,一旦在任务中,任务启动,问题就出现了!

更新2:调试时,一旦调试器到达行

int rowCount = _worksheetRange.Rows.Count;

它退出但没有任何反应,无法解释。

更新 3: 打开 Debug>Windows>Threads 后,显示如下:

enter image description here

Convert 方法调用上面的所有内容,定义如下:

public static async void Convert()
        {

            var excelDataConverter = new ExcelDataConverter(ExcelDataReader.ReadData());
            excelDataConverter.ConvertExelDataAsync();
        }

enter image description here

最佳答案

要添加到@StepehCleary 的回答中,消息本身就非常有用:

To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

您有一个进程外 Excel COM 对象的 COM 代理,该代理是在您的主线程(可能是 STA UI 线程)上创建的。然后您在工作池线程(这是一个 MTA 线程)上访问它。

虽然 COM 代理对象本身对于来自像这样的工作线程的调用可能是线程安全的,但在幕后它很可能试图将调用编码回最初创建代理的主线程。这就是死锁发生的地方。

为了安全起见,我建议您创建一个专用的 STA 线程来发送消息,在该线程上创建所有 COM 对象并在那里调用。

为此,我有两个辅助类,ThreadAffinityTaskSchedulerThreadWithAffinityContext,可用 here ,它们应该在任何执行环境中工作。

关于c# - 使用 Excel 数据的简单任务未完成运行导致 "ContextSwitchDeadlock",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23446497/

相关文章:

c# - 更改表中记录的排名

c# - AutoMapper,尝试并捕获映射

c# - 使用 ASP.NET 上传文件

Python:是否可以在不逐个单元格迭代的情况下删除一系列excel单元格中的值?

json - 如何使用 VBA 检索 JSON 响应?

c++ - 使用 W2A 将 BSTR 转换为 std::string 时,是否需要清理?

c++ - 处理不应崩溃的关键应用程序中的异常

C# 多对多关系

excel - 包含 "xlUp"或动态范围的公式?

c# - 在未安装 MS Office 的计算机上使用 Office.Interop.Excel