【发布时间】:2019-04-05 16:15:20
【问题描述】:
我有一个方法可以并行加载和运行报表布局。所有报告都将使用相同的baselayout.xml。由于线程每次尝试访问相同的资源时都会因异常而失败,因此我使用lock 锁定文件。
public static XmlTextReader LoadReport(string reportName)
{
object _locker = new object();
object reportData;
lock (_locker)
{
reportData = Resources.ResourceManager.GetObject(reportName);
}
return new XmlTextReader(new MemoryStream((byte[])reportData));
}
并行方法如下所示:
private void RunReportsParallel(List<ReportObject> coverterList)
{
try
{
Parallel.ForEach(coverterList, (currentObject) => {
currentObject.Convert();
});
}
catch (Exception e)
{
smlLogger.Error(Helper.SetLogLine(e.Message, processId));
throw;
}
}
Conver 将运行以下代码:
public override SectionReport GetMainReport()
{
SectionReport mainReport = new SectionReport();
XMLDataSource datasource = new XMLDataSource(null, "//AkontoRechnung");
datasource.LoadXML(rechnungsdaten.ToString());
mainReport = new ReportAkontorechnung(datasource, reportConfiguration, Language, NoPrintOut);
try
{
mainReport.Run();
}
catch (Exception e)
{
smlLogger.Error(Helper.SetLogLine(string.Format("Error creating Report: {0}", e.Message), processId));
throw;
}
return mainReport;
}
ReportAkontorechnung.cs 中引发错误的行:
this.LoadLayout(Helper.LoadReport("ReportAkontoZusammenfassung")); 最后,报错:
bei GrapeCity.ActiveReports.Controls.Image.Load(Stream stream, Boolean checkMagic)
bei GrapeCity.ActiveReports.SectionReport.#Pyb(XmlNode node)
bei GrapeCity.ActiveReports.SectionReport.#Qyb(XmlDocument layoutDoc, Boolean checkNames)
bei GrapeCity.ActiveReports.SectionReport.LoadLayout(XmlReader reader, ArrayList& errors)
bei GrapeCity.ActiveReports.SectionReport.LoadLayout(XmlReader reader)
bei GFPrinting.Domain.ReportAkontorechnung.InitializeReport()
in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\ReportAkontorechnung.cs:Zeile 108.
bei GFPrinting.Domain.ReportAkontorechnung..ctor(XMLDataSource reportNavigation, ReportConfiguration reportConfiguration, String reportLanguage, Boolean noPrintout)
in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\ReportAkontorechnung.cs:Zeile 79.
bei GFPrinting.Domain.Akontorechnung.GetMainReport()
in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\Akontorechnung.cs:Zeile 42.
bei GFPrinting.Domain.Change.ReportObject.Convert()
in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\ReportObject.cs:Zeile 33.
bei GFPrinting.Domain.Rechnungshandler.<>c.<RunReportsParallel>b__13_0(ReportObject currentObject)
in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\Rechnungshandler.cs:Zeile 103.
bei System.Threading.Tasks.Parallel.<>c__DisplayClass31_0`2.<ForEachWorker>b__0(Int32 i)
bei System.Threading.Tasks.Parallel.<>c__DisplayClass17_0`1.<ForWorker>b__1()
bei System.Threading.Tasks.Task.InnerInvoke()
bei System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
bei System.Threading.Tasks.Task.<>c__DisplayClass176_0.<ExecuteSelfReplicating>b__0(Object)
消息:
内部异常 1:NullReferenceException:Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt。客观事实 auf eine Objektinstanz festgelegt。 (对象引用不指向对象实例。)
如何解决返回null的问题?
编辑:
利亚姆的评论似乎解决了大多数问题。不使用并行加载,而是并行运行。我要注意错误才能看到这样的选项。
【问题讨论】:
-
我没有阅读所有代码,但是
LoadReport中的锁定似乎是错误的。您正在函数中创建一个新对象并将其用作锁定保护。这意味着每次调用该函数时,您都会锁定一个不同的对象:您的程序将永远不必等待。您需要将_locker的声明移到函数体之外 -
公平点,谢谢
-
你为什么不预先加载“报告”然后将它传递给你的并行任务呢?您确实需要尽可能避免
lock并行处理 -
@Peter
ReportAkontorechnung和ReportAkontorechnung.Run到底做了什么? 那些 调用 ActiveReports 并导致异常。调用栈显示异常是ReportAkontorechnung.InitializeReport()调用ActiveReports.SectionReport.LoadLayout时抛出的,不是你贴的代码 -
@Peter 并在您尚未发布的方法中引发异常。
ResourceManager.GetObject无论如何都是线程安全的。调用堆栈清楚地显示异常是由在InitializeReport中调用的ActiveReports 方法引发的。那个方法是LoadLayout
标签: c# multithreading xmlreader parallel.foreach activereports