Parallel.ForEach() 中的触发事件
Firing event in Parallel.ForEach()
我正在使用以下代码来加快从 COM 对象检索数据的速度:
const string status = "Getting node displacements...";
int count;
int totalCount;
IEnumerable<ILoadCase> loadCases;
ConcurrentBag<NodeDisplacements> nodeDisplacements;
// Check if results are even available
if (!this.HasResults)
return null;
// Get node displacements
nodeDisplacements = new ConcurrentBag<NodeDisplacements>();
loadCases = this.LoadCases.Cast<ILoadCase>().Union(this.LoadCombinations.Cast<ILoadCase>()).Where(lc => lc.ID >= StartLoadCase && lc.ID <= EndLoadCase);
count = 0;
totalCount = this.Nodes.Count * loadCases.Count();
Parallel.ForEach(this.Nodes, (node) => {
Parallel.ForEach(loadCases, (loadCase) => {
nodeDisplacements.Add(this.GetNodeDisplacements(node, loadCase));
this.OnModelBuildStatusUpdate(new ModelBuildStatusUpdateEventArgs(status, Interlocked.Increment(ref count), totalCount));
});
});
目前我正在通过命令提示符对此进行测试,跟踪 this.OnModelBuildStatusUpdate(...)
中触发的事件的进展情况。
由于并行循环,事件被触发多次。为了避免命令提示符被 "Getting node displacements..."
消息淹没,我尝试了这个:
private static string previouStatusMessage;
static void model_ModelBuildStatusUpdate(StaadModel sender, ModelBuildStatusUpdateEventArgs e)
{
if (string.IsNullOrEmpty(previouStatusMessage) || !previouStatusMessage.Equals(e.StatusMessage))
{
Console.WriteLine(e.StatusMessage);
previouStatusMessage = e.StatusMessage;
}
Console.Write("\r{0:0.00%}", e.ElementsProcessed / (double)e.TotalElementsToProcess);
}
只显示第一个状态消息,但此时显示多次(每个外循环线程一次?)。我想象我需要在这里锁定一些东西,但我不知道是什么。
如果有人能告诉我如何为此正确实施事件引发,我将不胜感激。
您的处理程序不是线程安全的。试试这个:
private static string previouStatusMessage;
private static object lockObject = new object();
static void model_ModelBuildStatusUpdate(StaadModel sender, ModelBuildStatusUpdateEventArgs e)
{
lock (lockObject)
{
if (string.IsNullOrEmpty(previouStatusMessage) || !previouStatusMessage.Equals(e.StatusMessage))
{
Console.WriteLine(e.StatusMessage);
previouStatusMessage = e.StatusMessage;
}
}
Console.Write("\r{0:0.00%}", e.ElementsProcessed / (double)e.TotalElementsToProcess);
}
我正在使用以下代码来加快从 COM 对象检索数据的速度:
const string status = "Getting node displacements...";
int count;
int totalCount;
IEnumerable<ILoadCase> loadCases;
ConcurrentBag<NodeDisplacements> nodeDisplacements;
// Check if results are even available
if (!this.HasResults)
return null;
// Get node displacements
nodeDisplacements = new ConcurrentBag<NodeDisplacements>();
loadCases = this.LoadCases.Cast<ILoadCase>().Union(this.LoadCombinations.Cast<ILoadCase>()).Where(lc => lc.ID >= StartLoadCase && lc.ID <= EndLoadCase);
count = 0;
totalCount = this.Nodes.Count * loadCases.Count();
Parallel.ForEach(this.Nodes, (node) => {
Parallel.ForEach(loadCases, (loadCase) => {
nodeDisplacements.Add(this.GetNodeDisplacements(node, loadCase));
this.OnModelBuildStatusUpdate(new ModelBuildStatusUpdateEventArgs(status, Interlocked.Increment(ref count), totalCount));
});
});
目前我正在通过命令提示符对此进行测试,跟踪 this.OnModelBuildStatusUpdate(...)
中触发的事件的进展情况。
由于并行循环,事件被触发多次。为了避免命令提示符被 "Getting node displacements..."
消息淹没,我尝试了这个:
private static string previouStatusMessage;
static void model_ModelBuildStatusUpdate(StaadModel sender, ModelBuildStatusUpdateEventArgs e)
{
if (string.IsNullOrEmpty(previouStatusMessage) || !previouStatusMessage.Equals(e.StatusMessage))
{
Console.WriteLine(e.StatusMessage);
previouStatusMessage = e.StatusMessage;
}
Console.Write("\r{0:0.00%}", e.ElementsProcessed / (double)e.TotalElementsToProcess);
}
只显示第一个状态消息,但此时显示多次(每个外循环线程一次?)。我想象我需要在这里锁定一些东西,但我不知道是什么。
如果有人能告诉我如何为此正确实施事件引发,我将不胜感激。
您的处理程序不是线程安全的。试试这个:
private static string previouStatusMessage;
private static object lockObject = new object();
static void model_ModelBuildStatusUpdate(StaadModel sender, ModelBuildStatusUpdateEventArgs e)
{
lock (lockObject)
{
if (string.IsNullOrEmpty(previouStatusMessage) || !previouStatusMessage.Equals(e.StatusMessage))
{
Console.WriteLine(e.StatusMessage);
previouStatusMessage = e.StatusMessage;
}
}
Console.Write("\r{0:0.00%}", e.ElementsProcessed / (double)e.TotalElementsToProcess);
}