0

ファイルのリストを調べて各ファイルから値を抽出し、それらをディクショナリに格納してディクショナリを返すメソッドを作成しました。このメソッドは大量のファイルを通過するため、ContextSwitchDeadLock エラーが発生します。このエラーを調査しましたが、スレッドを使用してこのエラーを修正する必要があります。私はスレッドにまったく慣れていないので、スレッドに関する助けが必要です。

新しいスレッドを作成し、delegate を使用してパラメーターのディクショナリとファイル名を 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 を使用している場合は、ConcurrentDictionaryおよびParallel.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())。

ただし、この方法では何も並行して行われないため、マルチスレッドの利点は得られません。できることは、複数のスレッドと複数の辞書 (スレッドごとに 1 つ) を持つことです。全員が完了すると、メイン スレッドはこれらすべての辞書をまとめることができます。

複数のスレッドが同じディクショナリにアクセスしたくない理由は、Dictionary クラスがスレッドセーフではないためです。複数のスレッドが同時に使用する場合、その動作は未定義です。ただし、 を使用できますがConcurrentDictionary、これはスレッドセーフです。これが意味することは、 に読み書きするたびにConcurrentDictionary、ロックを使用して、他の誰も辞書を同時に使用しなくなるまで確実に待機することです。

2 つの手法のどちらが高速かは、スレッドが共有ディクショナリにアクセスする頻度によって異なりますConcurrentDictionary。非常に頻繁にアクセスする場合は、複数の辞書を使用して最終的にマージすることをお勧めします。あなたの場合、ファイル 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.Joinafterを使用しThread.Startてスレッドの結果を取得し、クラス変数またはメイン プログラムとスレッドの両方が使用できるものを作成できますが、ポイントがわかりませんすべてのファイルを並行して処理したい場合を除き、ここでスレッドの。

于 2013-04-19T18:43:10.900 に答える