Проблема с параллельным выполнением

Мне нужно небольшое образование в отношении выполнения параллельных задач.

Я создал небольшую скрипку:

https://dotnetfiddle.net/JO2a4m

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

Код:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        var accounts = GenerateAccount();
        var accountsProcess = new List<Account>();
        var taskList = new List<Task>();
        var batch = 4;
        var count = 0;
        foreach (var account in accounts)
        {
            if (count == batch)
            {
                taskList.Add(new Task(() => ProcessAccount(accountsProcess)));
                count = 0;
                accountsProcess.Clear();
            }

            count++;
            accountsProcess.Add(account);
        }

        Parallel.ForEach(taskList, t =>
        {
            t.Start();
        }

        );
        Task.WaitAll(taskList.ToArray());
        if (accountsProcess.Count > 0)
            ProcessAccount(accountsProcess);
    }

    public static List<Account> GenerateAccount()
    {
        var accounts = new List<Account>();
        var first = "First";
        var second = "Second";
        for (int i = 0; i <= 1000; i++)
        {
            var account = new Account();
            account.first = first + i;
            account.second = second + i;
            accounts.Add(account);
        }

        return accounts;
    }

    public static void ProcessAccount(List<Account> accounts)
    {
        Console.WriteLine(accounts.Count);
        foreach (var account in accounts)
        {
            Console.WriteLine(account.first + account.second);
        }
    }
}

public class Account
{
    public string first;
    public string second;
}

person Navyseal    schedule 29.06.2018    source источник
comment
Не смешивайте TPL Parallel.xxxx с Task. 1) это плохо работает с вводом-выводом 2) Parallel.ForEach уже раскручивает поток, привязанный к процессору, зачем создавать/извлекать еще один из пула потоков через Task?   -  person MickyD    schedule 29.06.2018
comment
Кроме того, не рекомендуется использовать конструкторы Task. Задачи должны создаваться и запускаться с помощью Task.Run. Однако, как сказал MickyD, здесь нет смысла использовать задачи.   -  person ckuri    schedule 29.06.2018
comment
Ага. Спасибо за информацию. Я удалил и изменил его из своего исходного кода.   -  person Navyseal    schedule 30.06.2018


Ответы (1)


foreach (var account in accounts)
{
    if (count == batch)
    {
        taskList.Add(new Task(() => ProcessAccount(accountsProcess)));
        count = 0;
        accountsProcess.Clear();
    }

    count++;
    accountsProcess.Add(account);
}

Проблема в том, что все Task используют один и тот же объект List<Account>.

Я бы предложил изменить код на:

foreach (var account in accounts)
{
    if (count == batch)
    {
        var bob = accountsProcess;
        taskList.Add(new Task(() => ProcessAccount(bob)));
        count = 0;
        accountsProcess = new List<Account>();
    }

    count++;
    accountsProcess.Add(account);
}

Используя bob и назначая новый List для accountsProcess, мы гарантируем, что каждый Task получит свой собственный List, а не разделит один List.

Кроме того, рассмотрите возможность использования MoreLINQ Batch, а не собственного.

person mjwills    schedule 29.06.2018