2013-02-27 114 views
6

我需要創建隊列並將其與BackgroundWorker一起使用。所以我可以添加操作,接下來要做的事情是在後臺開始。我發現這個代碼由谷歌:使用隊列創建BackgroundWorker

public class QueuedBackgroundWorker<T> 
{ 
    public void QueueWorkItem(
     Queue queue, 
     T inputArgument, 
     Func<T> doWork, 
     Action workerCompleted) 
    { 
     if (queue == null) throw new ArgumentNullException("queue"); 

     BackgroundWorker bw = new BackgroundWorker(); 
     bw.WorkerReportsProgress = false; 
     bw.WorkerSupportsCancellation = false; 
     bw.DoWork += (sender, args) => 
     { 
      if (doWork != null) 
      { 
       args.Result = doWork(new DoWorkArgument<T>((T)args.Argument)); 
      } 
     }; 
     bw.RunWorkerCompleted += (sender, args) => 
     { 
      if (workerCompleted != null) 
      { 
       workerCompleted(new WorkerResult<T>((T)args.Result, args.Error)); 
      } 
      queue.Dequeue(); 
      if (queue.Count > 0) 
      { 
       QueueItem<T> nextItem = queue.Peek() as QueueItem<T>; 
       nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument); 
      } 
     }; 

     queue.Enqueue(new QueueItem<T>(bw, inputArgument)); 
     if (queue.Count == 1) 
     { 
      QueueItem<T> nextItem = queue.Peek() as QueueItem<T>; 
      nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument); 
     } 
    } 
} 

public class DoWorkArgument<T> 
{ 
    public DoWorkArgument(T argument) 
    { 
     this.Argument = argument; 
    } 
    public T Argument { get; private set; } 
} 

public class WorkerResult<T> 
{ 
    public WorkerResult(T result, Exception error) 
    { 
     this.Result = result; 
     this.Error = error; 
    } 

    public T Result { get; private set; } 
    public Exception Error { get; private set; } 
} 

public class QueueItem<T> 
{ 
    public QueueItem(BackgroundWorker backgroundWorker, T argument) 
    { 
     this.BackgroundWorker = backgroundWorker; 
     this.Argument = argument; 
    } 

    public T Argument { get; private set; } 
    public BackgroundWorker BackgroundWorker { get; private set; } 
} 

但我有doWork和workerCompleted問題。我收到錯誤:

Delegate 'Func' does not take 1 arguments

我該如何解決這個問題?我應該如何改變參數?由於

+1

至少表明上線。也許只能張貼那一行。 TL; DR – 2013-02-27 19:11:46

回答

20

這裏有一個更短的方法,你想要做什麼:

public class BackgroundQueue 
{ 
    private Task previousTask = Task.FromResult(true); 
    private object key = new object(); 
    public Task QueueTask(Action action) 
    { 
     lock (key) 
     { 
      previousTask = previousTask.ContinueWith(t => action() 
       , CancellationToken.None 
       , TaskContinuationOptions.None 
       , TaskScheduler.Default); 
      return previousTask; 
     } 
    } 

    public Task<T> QueueTask<T>(Func<T> work) 
    { 
     lock (key) 
     { 
      var task = previousTask.ContinueWith(t => work() 
       , CancellationToken.None 
       , TaskContinuationOptions.None 
       , TaskScheduler.Default); 
      previousTask = task; 
      return task; 
     } 
    } 
} 

通過增加每個新行動以前可以確保只有一個在時間製作的延續,作爲下一個項目在上一個項目完成之前不會啓動,您確保在沒有任何工作時沒有線程閒置,並且確保它們都按順序完成。

另請注意,如果您只認爲您需要一個隊列,而不是任何號碼,您可以使所有成員static,但這取決於您。

+0

看起來更好,謝謝你。現在我正在使用它:'bgQueue.QueueTask(()=> CreateConvertingProccess(item.FullName));'。你能幫我嗎?當一項任務完成後,我怎麼能調用方法?我應該在鎖後添加它嗎?我的意思是當我想添加方法,我將添加到RunWorkerCompleted。 – 2013-02-27 19:18:49

+0

非常感謝,它的工作。我必須學習如何使用Task。 – 2013-02-27 19:42:53

+0

請你再幫我一次。我如何知道隊列是否爲空? – 2013-02-28 13:17:22

0

看來你缺少第二個通用參數--Tout;

下面的代碼應該照顧它:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 

public static class QueuedBackgroundWorker 
{ 
    public static void QueueWorkItem<Tin, Tout>(
     Queue<QueueItem<Tin>> queue, 
     Tin inputArgument, 
     Func<DoWorkArgument<Tin>, Tout> doWork, 
     Action<WorkerResult<Tout>> workerCompleted) 
    { 
     if (queue == null) throw new ArgumentNullException("queue"); 

     BackgroundWorker bw = new BackgroundWorker(); 
     bw.WorkerReportsProgress = false; 
     bw.WorkerSupportsCancellation = false; 
     bw.DoWork += (sender, args) => 
      { 
       if (doWork != null) 
       { 
        args.Result = doWork(new DoWorkArgument<Tin>((Tin)args.Argument)); 
       } 
      }; 
     bw.RunWorkerCompleted += (sender, args) => 
      { 
       if (workerCompleted != null) 
       { 
        workerCompleted(new WorkerResult<Tout>((Tout)args.Result, args.Error)); 
       } 
       queue.Dequeue(); 
       if (queue.Count > 0) 
       { 
        QueueItem<Tin> nextItem = queue.Peek(); // as QueueItem<T>; 
        nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument); 
       } 
      }; 

     queue.Enqueue(new QueueItem<Tin>(bw, inputArgument)); 
     if (queue.Count == 1) 
     { 
      QueueItem<Tin> nextItem = queue.Peek() as QueueItem<Tin>; 
      nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument); 
     } 
    } 
} 

public class DoWorkArgument<T> 
{ 
    public DoWorkArgument(T argument) 
    { 
     this.Argument = argument; 
    } 

    public T Argument { get; private set; } 
} 

public class WorkerResult<T> 
{ 
    public WorkerResult(T result, Exception error) 
    { 
     this.Result = result; 
     this.Error = error; 
    } 

    public T Result { get; private set; } 

    public Exception Error { get; private set; } 
} 

public class QueueItem<T> 
{ 
    public QueueItem(BackgroundWorker backgroundWorker, T argument) 
    { 
     this.BackgroundWorker = backgroundWorker; 
     this.Argument = argument; 
    } 

    public T Argument { get; private set; } 

    public BackgroundWorker BackgroundWorker { get; private set; } 
} 

和使用應該是:

private readonly Queue<QueueItem<int>> _workerQueue = new Queue<QueueItem<int>>(); 
    private int _workerId = 1; 

    [Test] 
    public void BackgroundTest() 
    { 
     QueuedBackgroundWorker.QueueWorkItem(
      this._workerQueue, 
      this._workerId++, 
      args => // DoWork 
       { 
        var currentTaskId = args.Argument; 
        var now = DateTime.Now.ToLongTimeString(); 
        var message = string.Format("DoWork thread started at '{0}': Task Number={1}", now, currentTaskId); 
        return new { WorkerId = currentTaskId, Message = message }; 
       }, 
      args => // RunWorkerCompleted 
       { 
        var currentWorkerId = args.Result.WorkerId; 
        var msg = args.Result.Message; 

        var now = DateTime.Now.ToShortTimeString(); 
        var completeMessage = string.Format(
         "RunWorkerCompleted completed at '{0}'; for Task Number={1}, DoWork Message={2}", 
         now, 
         currentWorkerId, 
         msg); 
       } 
      ); 
    }