2013-02-27 19 views
6

Potrzebuję utworzyć kolejkę i używać go z BackgroundWorker. Mogę więc dodawać operacje, a kiedy już skończysz, zaczyna się w tle. Znalazłem ten kod przez google:Tworzenie BackgroundWorker z Queue

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; } 
} 

Ale mam problem z doWork i workerCompleted. Pojawia się błąd:

Delegate 'Func' does not take 1 arguments

Jak mogę to naprawić? Jak mam zmienić parametry? Dzięki

+1

Przynajmniej wskazują na która linię. A może tylko opublikować tę linię. TL; DR –

Odpowiedz

20

Oto znacznie krótsza metoda, która robi to, co chcesz:

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; 
     } 
    } 
} 

Dodając każdą nową akcję jako kontynuacja poprzedniego upewnić się, że jest tylko jeden pracował w czasie, jako następnego elementu nie zacznie się, dopóki poprzedni element nie zostanie ukończony, upewnisz się, że nie ma nic na siedząco wokół biegu jałowego, kiedy nie ma nic, nad czym możesz pracować, i upewniasz się, że wszystko jest zrobione w porządku.

Należy również pamiętać, że jeśli myślisz, że będziesz potrzebować tylko jednej kolejki, a nie żadnej liczby, możesz utworzyć wszystkich członków static, ale to zależy od Ciebie.

+0

Wygląda lepiej, dzięki za to. Teraz używam go w ten sposób: 'bgQueue.QueueTask (() => CreateConvertingProccess (item.FullName));'. Czy możesz mi pomóc w jaki sposób mogę wywołać metodę, gdy wykonywane jest jedno zadanie? Czy powinienem dodać go po zamknięciu? Mam na myśli, kiedy chcę dodać metodę, którą chciałbym dodać do RunWorkerCompleted. –

+0

Dziękuję bardzo, działa. Muszę się nauczyć o pracy z Task. –

+0

Czy możesz mi jeszcze raz pomóc, proszę. Jak mogę się dowiedzieć, czy kolejka jest pusta? –

0

Wygląda na to, że brakuje drugiego parametru ogólnego - Tout;

Poniższy kod należy dbać o to:

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; } 
} 

A użycie powinno być:

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); 
       } 
      ); 
    } 
Powiązane problemy