2

「作成に費用がかかる」データを読み取ってキャッシュする、頻繁に使用される.Net 3.5アプリケーションがあります。アプリケーションは、「別のプロセスによって使用されていない」ことに基づいてファイルを読み書きします。他のプロセスがファイルの読み取りと書き込みを行っている場合、アプリケーションは (しばらくの間) スリープ状態になり、再試行します。これはファイルを読み書きする正しい方法ですか? お知らせ下さい。

public void Add<T>(string key, CacheItem<T> item)
        {
            bool fileInUse = false;
            while (!fileInUse)
            {
                try
                {
                    using (Stream stream = new FileStream(Path.Combine(cachePath, key+".bin"), FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        Serializer.NonGeneric.Serialize(stream, item);
                    }
                    fileInUse = true;
                }
                catch (IOException ex)
                {
                    if (ex.Message.Contains("being used by another process"))
                    {
                        //Poll till the file is free to be used by this process
                        Thread.Sleep(100);
                        fileInUse = false;
                    }
                }
            }            
        }        

public CacheItem<T> Get<T>(string key, Type type)
        {
            CacheItem<T> item = null;

            FileInfo fileInfo = new FileInfo(Path.Combine(cachePath, key+".bin"));
            fileInfo.Refresh();
            if (fileInfo.Exists)
            {
                bool fileInUse = false;
                while (!fileInUse)
                {
                    try
                    {
                        using (Stream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.None))
                        {
                            object objectTemp = Serializer.NonGeneric.Deserialize(type, stream);
                            item = (CacheItem<T>)objectTemp;
                        }
                        fileInUse = true;
                    }
                    catch(IOException ex) 
                    {
                        if (ex.Message.Contains("being used by another process"))
                        {
                            //Poll till the file is free to be used by this process
                            Thread.Sleep(100);
                            fileInUse = false;
                        }
                    }
                }               
            }                       
            return item;                                   
        }
4

2 に答える 2

2

その上にグローバルミューテックスを追加して、絶対に必要以上に待機することを避けることができます。

グローバル ミューテックスは、空でない値nameMutex Constructorに渡すことによって作成されます。

利点:

  • Mutex を使用すると、平均で 50 ミリ秒待つのではなく、ファイルが利用可能になった直後にウェイクアップできます。
  • Mutex を使用すると、睡眠と覚醒を繰り返す代わりに、一度眠り、一度目覚めることができます。スリープ状態のスレッドは、OS によって非常に効率的に処理され、リソースをほとんど消費しません。
  • ミューテックスを取得すると、成功するまでに何度も失敗する可能性はなく、ほぼ 100% の確率でファイルを開くことができます。

全体として、高速になるだけでなく、プロセスで消費するCPU サイクルが少なくなる可能性があります。

于 2012-04-13T19:25:44.713 に答える
1

これがあなたが頻繁に行っていることである場合は、まったく別の設計をお勧めします (したがって、パフォーマンスが問題になります)。

文字列(および複数のファイルで機能する場合はファイル名)を取るパブリック静的メソッド(またはシングルトンのメソッド)が必要です。そのメソッドでは、その文字列をBlockingCollection<string>. Dictionary<string, BlockingCollection<string>>(ファイル名をそのファイルのキューにマップする を介して、1 つだけ、またはファイルごとに 1 つ持つことができます。)

ほとんどの場合 (つまり、バッファがいっぱいではない場合)、ファイルに何かを書き込もうとするタスクは、それをキューに追加するだけで、すぐに作業に戻ります。

次に、ブロッキング コレクションからの読み取り (多数のブロッキング コレクションがある場合でも、必要なのは 1 つだけです) とデータのファイルへの書き込みだけを行う別のスレッド/タスクが必要です。ファイルに書き込むスレッドは 1 つしかないため、ファイル IO を回避する必要があるロックはなくBlockingCollection、このプロデューサー/コンシューマー モデルで動作するように設計されており、必要なすべてのロックを処理します。

BlockingColleciton複数のキューを処理しようとする説得力のあるパフォーマンス上の理由が見つからない限り、すべてのファイルに対して1 つのみを使用することをお勧めします。管理がだいぶ楽になります。

于 2012-04-13T19:33:28.997 に答える