2013-02-27 48 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); 
       } 
      ); 
    }