リアルタイムで更新する必要があるデータ セットのリストがあります。一度に 100 以上のうち 10 を処理し、1 つが完了したら、次に古い行を取得したいと思います。基本的に、このループを無限に続けます。私はスレッド化の世界にまったく慣れておらず、AsyncTask をいじっています。誰かが私に指摘できる例はありますか? 私はかなりグーグルで検索しましたが、探しているものを正確に見つけることができません。
2 に答える
少なくとも .Net 4.5 では、非同期プログラミングは非常に甘いものになっています。
簡単な例を次に示します。
public async void DoAsync()
{
await Task.Run( () =>
{
// Do task!
} );
}
public async Task<string> GetStringAsync()
{
string s = "";
await Task.Run( () =>
{
for(int I = 0; I < 9999999; I++)
{
s += I.ToString();
}
}
return s;
}
役立つリソース
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
AsyncTask
1 回限りの操作に適しています。進行中のタスクについては、ワーカー スレッドを検討できます。
免責事項: これが最善の方法であるとは言いませんが、いくつかのアイデアや参考になる情報が得られるはずです。
public class ThreadingSample : IDisposable
{
private Queue<SomeObject> _processingQueue = new Queue<SomeObject>();
private Thread _worker;
private volatile bool _workerTerminateSignal = false;
private EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
public bool HasQueuedItem
{
get
{
lock(_processingQueue)
{
return _processingQueue.Any();
}
}
}
public SomeObject NextQueuedItem
{
get
{
if ( !HasQueuedItem )
return null;
lock(_processingQueue)
{
return _processingQueue.Dequeue();
}
}
}
public void AddItem(SomeObject item)
{
lock(_processingQueue)
{
_processingQueue.Enqueue(item);
}
_waitHandle.Set();
}
public ThreadingSample()
{
_worker = new Thread(ProcessQueue);
_worker.Start();
}
private void ProcessQueue()
{
while(!_workerTerminateSignal)
{
if ( !HasQueuedItem )
{
Console.WriteLine("No items, waiting.");
_waitHandle.WaitOne();
Console.WriteLine("Waking up...");
}
var item = NextQueuedItem;
if (item != null) // Item can be missing if woken up when the worker is being cleaned up and closed.
Console.WriteLine(string.Format("Worker processing item: {0}", item.Data));
}
}
public void Dispose()
{
if (_worker != null)
{
_workerTerminateSignal = true;
_waitHandle.Set();
if ( !_worker.Join( TimeSpan.FromMinutes( 1 ) ) )
{
Console.WriteLine("Worker busy, aborting the thread.");
_worker.Abort();
}
_worker = null;
}
}
public class SomeObject
{
public string Data
{
get;
set;
}
}
}
テストする ユニットテストを使用して開始します。単体テストを適切なテストに拡張して、アクションが期待どおりに実行されていることを確認できます。私の場合、それらは動作を急上昇させるための適切な最初のアサーションです。
[Test]
public void TestThreading()
{
using ( var sample = new ThreadingSample() )
{
sample.AddItem(new ThreadingSample.SomeObject {Data = "First Item"});
sample.AddItem(new ThreadingSample.SomeObject {Data = "Second Item"});
Thread.Sleep(50);
sample.AddItem(new ThreadingSample.SomeObject {Data = "Third Item"});
}
}
テストからの関連する出力:
------ テスト開始: アセンブリ: NHMapping.dll ------
ワーカー処理アイテム: 最初のアイテム
ワーカー処理アイテム: 2 番目のアイテム アイテム
なし、待機中。
起きています...
アイテムはありません、待っています。
目を覚ます...
ワーカー処理アイテム: 3 番目のアイテム アイテム
はありません。待機中です。
ウェイクアップ...
1 回成功、0 回失敗、0 回スキップ、0.12 秒かかりました (アドホック)。
ここでは、ワーカーがスリープ状態になり、キュー内のアイテムを処理するためにウェイクアップする様子を確認できます。技術的には、リストを使用して、ロックから解放する前にリストから 10 個のアイテムをフェッチし、それらの 10 個のアイテムを処理してからリストを再度チェックすることができます。
クラスが破棄されると、ループが解放され、ワーカー スレッドが終了するまでしばらく待ってから中止します。ここでは、未処理のアイテムをチェックし、それらが処理されないことをログに記録するか、後で処理するためにファイルに保持する必要があります。
編集:ダブルイベントの問題が見つかりました...より良い実装はManualReset
、EventWaitHandle
private EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
次に、アイテムを処理するケースを処理するときに、ハンドルを再送信します。
var item = NextQueuedItem;
if (item != null) // Item can be missing if woken up when the worker is being cleaned up and closed.
{
Console.WriteLine(string.Format("Worker processing item: {0}", item.Data));
_waitHandle.Reset();
}
これにより、より良いテスト結果が得られます。
------ テスト開始: アセンブリ: NHMapping.dll ------
ワーカー処理アイテム: 最初のアイテム
ワーカー処理アイテム: 2 番目のアイテム アイテム
なし、待機中。
目を覚ます...
ワーカー処理アイテム: 3 番目のアイテム アイテム
はありません。待機中です。
ウェイクアップ...
1 回成功、0 回失敗、0 回スキップ、0.13 秒かかりました (アドホック)。