excel - 为什么并行化代码不会写入 Excel 电子表格?
问题描述
在电子表格中编写许多工作Excel
表可能需要一段时间。并行化它会很有帮助。
此代码运行良好,它Excel
在屏幕上弹出一个电子表格,其中包含四个名为Sheet1
、1
、2
和的工作表3
。
open Microsoft.Office.Interop.Excel
open FSharp.Collections.ParallelSeq
let backtestWorksheets = [1..3]
let app = new ApplicationClass(Visible = true)
let workbook = app.Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
let writeInfoSheet (worksheet: Worksheet) : unit =
let foo i =
let si = string i
worksheet.Range("A" + si, "A" + si).Value2 <- "Hello " + si
List.iter foo [1..10]
let wfm = [1, writeInfoSheet; 2, writeInfoSheet; 3, writeInfoSheet]
|> Map.ofList
let adder (workbook : Workbook)
(i : int)
: unit =
let sheet = workbook.Worksheets.Add() :?> Worksheet
sheet.Name <- string i
wfm.[i] sheet
List.iter (adder workbook) backtestWorksheets
//PSeq.iter (adder workbook) backtestWorksheets
[<EntryPoint>]
let main argv =
printfn "%A" argv
0 // return an integer exit code
但是,用它下面的注释行替换开头List.iter
的行会弹出一个带有相同四个工作表的电子表格,但所有工作表都是空白的。
所以我的问题是:为什么不能用 PSeq 并行化代码写入 Excel?
评论:
最初我有一个不同的问题。可能是因为在我的应用程序中,当我尝试运行与上述类似的代码时,工作表更重,PSeq
但有一个异常提示
Unhandled Exception: System.TypeInitializationException: The type initializer for '<StartupCode$Fractal13>.$Program' threw an exception. ---> System.AggregateException: One or more errors occurred. ---> System.Runtime.InteropServices.COMException: The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))
List.iter
替换不会发生这种情况PSeq.iter
。
我无法在足够简单的上下文中复制此异常以成为适当的 SO 问题,但我仍然会对处理它的任何建议感兴趣。
解决方案
看起来Microsoft.Office.Interop.Excel
代码从未设计为一次从多个线程调用。这是有人在 MS Office 论坛中提出的关于在多个线程中进行更新(在 C# 中)的问题。我将在此处引用该答案的相关部分:
使用多线程在多个工作表中进行搜索最终会使用 Excel 的核心 - Excel.Application 对象,这意味着线程需要排队以一次运行一个,从而剥夺了应用程序所需的性能改进。
[...]
所有这一切都是因为 Office 对象模型不是线程安全的。
如果您在命名空间中调用任何内容,您似乎就无法使用非并行设计Microsoft.Office.Interop
。
编辑: Aaron M. Eshbach在评论中提出了一个很好的建议:在多个线程上完成所有后台工作,并使用 aMailboxProcessor
对电子表格进行实际更新。MailboxProcessor 的消息队列会自动为您序列化更新操作,您不需要额外的工作。
推荐阅读
- java - HierarchyStruc 类中 Java 中的 ClassCastException 如下
- android - Google 登录与 Google Play 服务登录
- java - jooq 从 sql 文件插入
- apache-spark - 在 Pyspark Mllib 代码中使用 0 在阶段 n 中等待
- reactjs - 未捕获的语法错误:意外的标记“<”
- javascript - 如何从 React 中的道具循环嵌套对象?
- ios - 键盘出现时移动视图
- powershell - 如何将数组参数从电源外壳传递到手臂模板
- invoice - 保存时出错... Quickbooks 错误消息:此用户不允许此交易操作
- c++ - 在 linux 集群上运行 windows C++ 代码