Parallel.ForEach в .NET 4.0 - PullRequest
       42

Parallel.ForEach в .NET 4.0

2 голосов
/ 18 января 2012
    private static Int64 DirectoryBytes(String path)
    {
        var files = Directory.EnumerateFiles(path);
        Int64 masterTotal = 0;
        ParallelLoopResult result = Parallel.ForEach<String, Int64>(
        files,
        () =>
        { // localInit: Invoked once per task at start
            // Initialize that this task has seen 0 bytes
            return 0; // Set taskLocalTotal initial value to 0
        },
        (file, loopState, index, taskLocalTotal) =>
        { // body: Invoked once per work item
            // Get this file's size and add it to this task's running total
            Int64 fileLength = 0;
            FileStream fs = null;
            try
            {
                fs = File.OpenRead(file);
                fileLength = fs.Length;
            }
            catch (IOException) { /* Ignore any files we can't access */ }
            finally { if (fs != null) fs.Dispose(); }
            return taskLocalTotal + fileLength;
        },
        taskLocalTotal =>
        { // localFinally: Invoked once per task at end
            // Atomically add this task's total to the "master" total
            Interlocked.Add(ref masterTotal, taskLocalTotal);
        });
        return masterTotal;
    }

Это кусок кода, который я получил из книги. У меня есть сомнения в этом. Переменная tasklocaltotal будет на уровне потока или на уровне задачи. Согласно книге это на уровне задач, но поскольку поток может выполнять несколько задач, то почему переменная сохраняет свое значение на протяжении всего выполнения программы. Я думаю, что это должно быть на уровне потока.

Может ли кто-нибудь рассказать об этом и, возможно, получить дополнительные ссылки, чтобы прочитать, где я могу получить более четкое представление об этом.

1 Ответ

1 голос
/ 18 января 2012

Перегрузка ForEach , которая используется здесь, указывает, что последний параметр является действием, которое вызывается для каждой завершенной задачи.

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

Запутанная часть этой части:

taskLocalTotal =>
{ 
   // localFinally: Invoked once per task at end
   // Atomically add this task's total to the "master" total
   Interlocked.Add(ref masterTotal, taskLocalTotal);
}

Просто подумайте об этом как (вы можете даже написать это):

x =>
{ 
   // localFinally: Invoked once per task at end
   // Atomically add this task's total to the "master" total
   Interlocked.Add(ref masterTotal, x);
}

TaskLocalTotal, к сожалению, имеет то же имя, что и в действии Задачи.

Так что это не та же самая переменная, а просто то же имя.

...