0

我编写了一个方法,它遍历文件列表并从每个文件中提取值并将它们存储到字典中并返回字典。此方法遍历大量文件,因此我收到 ContextSwitchDeadLock 错误。我已经调查了这个错误,我需要使用一个线程来修复这个错误。我是线程的新手,希望得到线程方面的帮助。

我创建了一个新线程并使用委托将参数字典和文件名传递到方法 getValuesNew()。我想知道如何返回字典。我附上了我想调用的方法以及创建新线程的主程序中的代码。任何改进我的代码的建议将不胜感激!

            //dictionary and fileNames are manipulated a bit before use in thread
            Dictionary<string, List<double>> dictionary = new Dictionary<string, List<double>>();
            List<string> fileNames = new List<string>();

            ...

            Thread thread = new Thread(delegate()
            {
                 getValuesNEW(dictionary, fileNames);
            });

            thread.Start();


   //This is the method that I am calling
   public Dictionary<string, List<double>> getValuesNEW(Dictionary<string, List<double>> dictionary, List<string> fileNames)
    {
        foreach (string name in fileNames)
        {
            XmlReader reader = XmlReader.Create(name);
            var collectValues = false;
            string ertNumber = null;
            while (reader.Read())
            {
                if ((reader.NodeType == XmlNodeType.Element))
                {
                    if (reader.Name == "ChannelID" && reader.HasAttributes)
                    {
                        if (dictionary.ContainsKey(sep(reader.GetAttribute("EndPointChannelID"))))
                        {
                            //collectValues = sep(reader.GetAttribute("EndPointChannelID")) == ertNumber;
                            collectValues = true;
                            ertNumber = sep(reader.GetAttribute("EndPointChannelID"));
                        }

                        else
                        {
                            collectValues = false;
                        }
                    }
                    else if (collectValues && reader.Name == "Reading" && reader.HasAttributes)
                    {
                        dictionary[ertNumber].Add(Convert.ToDouble(reader.GetAttribute("Value")));
                    }

                }
            }
        }
        return dictionary;
    }
4

3 回答 3

1

其他人已经解释了为什么当前的方法无法让您有所作为。如果您使用的是 .NET 4,则可以使用ConcurrentDictionaryandParallel.ForEach

private List<double> GetValuesFromFile(string fileName)
{
      //TBD
}

private void RetrieveAllFileValues()
{
     IEnumerable<string> files = ...;
     ConcurrentDictionary<int, List<double>> dict = new ConcurrentDictionary<int, List<double>>();
     Parallel.ForEach(files, file =>
           {
               var values = GetValuesFromFile(file);
               dict.Add(file, values);
           });
}
于 2013-04-19T18:47:06.557 回答
0

您不需要返回字典:主线程已经引用了它,它会看到您的线程所做的更改。主线程所要做的就是等到委托线程完成(例如使用thread.Wait())。

但是,以这种方式做事,您不会从多线程中受益,因为没有任何事情是并行完成的。您可以做的是拥有多个线程和多个字典(每个线程一个)。当每个人都完成后,主线程可以将所有这些字典放在一起。

您不希望多个线程访问同一个字典的原因是 Dictionary 类不是线程安全的:如果多个线程同时使用它,它的行为是未定义的。但是你可以使用 a ConcurrentDictionary,这个是线程安全的。这意味着每次读取或写入 时ConcurrentDictionary,它都会使用锁来确保等到没有其他人同时使用字典。

这两种技术中哪一种更快取决于您的线程访问共享字典的频率:如果它们很少访问它,那么 aConcurrentDictionary将运行良好。如果他们经常访问它,那么最好使用多个字典并最终合并。在您的情况下,由于涉及文件 I/O,我怀疑这种ConcurrentDictionary方法效果最好。

因此,简而言之,将 getValuesNEW 更改为:

//This is the method that I am calling
public void getValuesNEW(ConcurrentDictionary<string, List<double>> dictionary, List<string> fileNames)
 {
     foreach (string name in fileNames)
     {
         // (code in there is unchanged)
     }
     // no need to return the dictionary
     //return dictionary;
 }
于 2013-04-19T18:42:26.803 回答
0

如果你想等待你的线程完成,那么你可以使用Thread.JoinafterThread.Start来获取你的线程的结果,创建一个类变量或者你的主程序和你的线程都可以使用的东西,但是,我不明白这一点这里是一个线程,除非您想并行处理所有文件。

于 2013-04-19T18:43:10.900 回答