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