我有一个程序,当单击一个按钮时会创建两个pdf文件。它在WinForms中使用Microsoft Office interop,文件创建如下:
*该应用程序一词对用户不可见
它本身可以很好地工作,但是完成两个文件需要8秒钟,因此我尝试使用多线程,这样用户就不必等待并且可以处理其他事情或继续执行步骤1再次。
但是,它会引发各种错误; COM,RPC等,即使在数据库连接中也是如此,我认为原因是因为有两个单独的线程在工作,并且使用相同的资源,所以在某个时间点上,另一个可能关闭了另一个线程的资源。正在/即将使用因此,我尝试使用join(),以便另一个线程可以先完成其工作,关闭其各自的资源,然后继续进行下一个。
这很好,如果用户没有单击该按钮来创建另一个文件,那么该文件将在另一个文件之后创建(如果用户完成第一步的速度比预期的快)
join()
足以处理错误以及在后台处理文件创建,但是,我想处理在文件创建之后紧接着进行的情况,因为在这种情况下,然后,由于线程彼此等待,因此该过程似乎是线性的,除此之外,还会产生瓶颈,其中线程现在排成一行并阻塞了主线程,这使用户等待12秒或更长时间。
我想知道/需要澄清的是]
interop
的两个文件使用不同的资源,以免产生错误吗?join()
还是有其他替代方法,其中它不阻塞UI线程或主线程?这样,文件创建线程仅在后台排队(彼此仍在等待完成),而无需用户等待。这是我的代码;
用于创建文档的模块中的过程和公共变量:
Public tsThread As Thread
Public psThread As Thread
Sub SaveDoc(docType,someArgs)
Dim wordApp = New Word.Application
Dim templateBookmarks As Word.Bookmarks
Dim templateName As String
Dim template As New Word.Document
wordApp = CreateObject("Word.Application")
Select Case docType
Case "Type1"
templateName = "SampleType.docx"
template = wordApp.Documents.Add(templatePath & templateName)
templateBookmarks = template.Bookmarks
templateBookmarks.Item("bookmarkInWord").Range.Text = "Foo"
template.Tables(1).Cell(msWordRow, 1).Range.Text = "Value in cell 1"
Case "Type2"
‘Same thing, just different values and template
Case "Type3"
End select
template.SaveAs2(savePath & saveName, Word.WdSaveFormat.wdFormatPDF)
wordApp.ActiveDocument.Close(Word.WdSaveOptions.wdDoNotSaveChanges)
wordApp.Quit()
End Sub
单击按钮时在子窗体中的过程:
If Not IsNothing(tsThread) Then
If tsThread.IsAlive Then
tsThread.Join()
End If
End If
If Not IsNothing(psThread) Then
If psThread.IsAlive Then
psThread.Join()
End If
End If
tsThread = New Thread(Sub() SaveDoc(docType1,someArgs))
tsThread.Start()
If Not IsNothing(tsThread) Then
If tsThread.IsAlive Then
tsThread.Join()
End If
End If
psThread = New Thread(Sub() SaveDoc(docType2,someArgs))
psThread.Start()
If records = maxRecords Then
If psThread.IsAlive or tsThread.isAlive Then
tsThread.Join()
psThread.Join()
Dim fooThread = New Thread(Sub() SaveDoc(docType3,someArgs))
fooThread.Start()
End If
End If
SwitchForm("Child Form for Step 1")
End Sub
错误,即不使用join()
的错误通常在代码的以下部分中:
wordApp.ActiveDocument.Close(Word.WdSaveOptions.wdDoNotSaveChanges)
或在
wordApp.Quit()
或在书签中
templateBookmarks.Item("bookmarkInWord").Range.Text = "Foo"
或者有时在其中一种情况下的不同时间或在数据库连接过程中的任何地方。
我对多线程技术以及Interop女士还是比较陌生,因此如果我有任何误解,请寻求帮助。代码在VB中,但是我也可以理解C#。任何帮助/指导,不胜感激。谢谢!
我会考虑使用生产者/消费者模式。当用户单击按钮时,主线程将生成要处理的文档,而后台线程将使用文档并进行处理。 blocking collection通常可以用作两个线程之间的接口。
另一种选择是limited concurrency task scheduler。这使您可以安排任务以进行处理,同时确保仅同时处理一个(或其他一些限制)。
我的建议是创建一个具有嵌入式宏VBA程序的启用宏的模板,该程序执行所有书签并保存为PDF。这样可以将Interop调用减少为仅创建/处理Word应用程序并使用传入的参数运行VBA过程。