2013-03-15 6 views
2

Я пытаюсь выполнить некоторую задачу фильтрации с помощью TPL. Здесь я упрощаю код для фильтрации числа, основанного на условии. Вот код.Получение странного результата при использовании параллельной библиотеки задач?

public static void Main (string[] args) 
    { 
     IEnumerable<int> allData = getIntData(); 

     Console.WriteLine ("Complete Data display"); 
     foreach (var item in allData) { 
      Console.Write(item); 
      Console.Write(" | "); 
     } 

     Console.WriteLine(); 
     filterAllDatas (ref allData, getConditions()); 

     foreach (var item in allData) { 
      Console.Write(item); 
      Console.Write(" | "); 
     } 
     Console.WriteLine(); 
    } 

    static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int,bool>> conditions) 
    { 
     List<int> filteredData = data.ToList(); 
     List<Task> tasks = new List<Task>(); 
     foreach (var item in data.AsParallel()) { 
      foreach (var condition in conditions.AsParallel()) { 

       tasks.Add(Task.Factory.StartNew(() => { 
        if (condition(item)) { 
         filteredData.Remove(item); 
        } 
       })); 

      } 
     } 
     Task.WaitAll(tasks.ToArray()); 
     data = filteredData.AsEnumerable(); 
    } 
    static IEnumerable<Func<int,bool>> getConditions() 
    { 
     yield return (a) => { Console.WriteLine("modulo by 2"); return a % 2 == 0;}; 
     yield return (a) => { Console.WriteLine("modulo by 3"); Thread.Sleep(3000); return a % 3 == 0;}; 

    } 
    static IEnumerable<int> getIntData() 
    { 
     for (int i = 0; i < 10; i++) { 
      yield return i; 
     } 
    } 

Здесь вы можете просто отфильтровать целое число, разделенное на два или три. Теперь, если я удалю этот поток кода сна, работайте отлично, но если я полагаю, что это не так.

Обычно означает без Thread.Sleep, оба условия выполняют 10 раз, например. для каждого числа. Но если я добавлю, что первое условие Thread.Sleep выполняется 7 раз, а второй выполняется тринадцать раз. И из-за этого несколько чисел пропустите условие. Я пытаюсь отлаживать, но не получил ничего, что могло бы указывать на проблему с моим кодом.

Есть ли хороший способ достичь этого? Как условие фильтра на данных может работать как асинхронно, так и параллельно, чтобы повысить производительность?

Код предназначено только для демонстрационных целей.

FYI: В настоящее время я использую Mono с студией Xamarine на машине для окон.

Пожалуйста, дайте мне знать, если потребуется какая-либо дополнительная информация.

+0

Как и где 'getData' определены? –

+0

@ Геннадий Ванин - Новосибирск извиняюсь за типографию ... Я отредактировал его ... – kunjee

ответ

1

Сначала вы можете изменить метод getConditions, чтобы увидеть, что происходит внутри:

static IEnumerable<Func<int, bool>> getConditions() 
{ 
    yield return (a) => { Console.WriteLine(a + " modulo by 2"); return a % 2 == 0; }; 
    yield return (a) => { Console.WriteLine(a + " modulo by 3"); Thread.Sleep(3000); return a % 3 == 0; }; 
} 

А если остановить захват переменных Foreach, он будет работать:

static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int, bool>> conditions) 
{ 
    List<int> filteredData = data.ToList(); 
    List<Task> tasks = new List<Task>(); 
    foreach (var item in data.AsParallel()) 
    { 
     var i = item; 
     foreach (var condition in conditions.AsParallel()) 
     { 
      var c = condition; 
      tasks.Add(Task.Factory.StartNew(() => 
      { 
       if (c(i)) 
       { 
        filteredData.Remove(i); 
       } 
      })); 

     } 
    } 
    Task.WaitAll(tasks.ToArray()); 
    data = filteredData.AsEnumerable(); 
} 
+0

Выбор вашего ответа в ответе как Это вы объясняете. Пожалуйста, поддержите ответ мата, как он был первым. :) – kunjee

2

Я бы предположил, что это связано с тем, как лямбда вашей задачи закрывается по переменной цикла condition. Попробуйте изменить его следующим образом:

 foreach (var condition in conditions.AsParallel()) { 
      var tasksCondition = condition 
      tasks.Add(Task.Factory.StartNew(() => { 
       if (tasksCondition(item)) { 
        filteredData.Remove(item); 
       } 
      })); 

Примечание вы также закрытия над переменной цикла item, что может вызвать подобные проблемы.

+0

Это сработало ... Черт, я падаю за этим типом ловушки ... Спасибо ... Но я не понял, о чем вы говорили замыкающий цикл, если вы можете объяснить, что это будет здорово. – kunjee

Смежные вопросы