Parallel.ForEach()中的射击事件

时间:2015-07-15 06:32:29

标签: c# .net events 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);
        }

仅显示第一个状态消息,但此时它会多次显示(每个外部循环线程一次?)。我成像我需要锁定一些东西,但我无法弄清楚是什么。

如果有人能告诉我如何正确地为此举办活动,我会很感激。

1 个答案:

答案 0 :(得分:3)

您的处理程序不是线程安全的。试试这个:

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);
    }