Как я могу использовать Parallel For в TPL вместо while - PullRequest
1 голос
/ 13 февраля 2012

Я хочу использовать параллельное выражение для оператора вместо оператора while.Когда я смотрю на сэмплы, Parallel For запускается только с известной -или переменной-count.

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

Я собираюсь попробовать простой тест производительности с TPL и классическим кодом.Итак, я пишу класс модуля, который вычисляет модуль с операцией декремента.Моя функция похожа на

long FindModulus(long n, int i)
{
    while ( n >= i )
       n -= i;
    return  n;
}

Моя цель - заменить этот цикл параллельным циклом For

, и я также хочу узнать, могу ли я использовать Parallel For с оператором if и break.

Я думаю, что мне понадобится блокировка, потому что значение n будет изменено во всех потоках, будет полезен любой пример кода

Заранее спасибо

Ответы [ 4 ]

4 голосов
/ 13 февраля 2012

Я бы написал MyParallel класс, как показано ниже

public static class MyParallel
{
    public static void While(Func<bool> condition, Action action)
    {
        Parallel.ForEach(WhileTrue(condition), _ => action());
    }

    static IEnumerable<bool> WhileTrue(Func<bool> condition)
    {
        while (condition()) yield return true;
    }
}

и используйте это так.

int i=0;
MyParallel.While( 
    () => {
        lock (SomeLockObject)
        {
            return i++<10;
        }
    },  
    () => Console.WriteLine("test")
);

Не забудьте заблокировать общие объекты (если вы их измените), используемые в condition / action

4 голосов
/ 13 февраля 2012

, если вы не знаете, сколько раз цикл пройдет Parallel.For - не вариант. Но вы можете легко использовать простые задачи и сделать это для себя:

object syncRoot = new object();
bool finished = false;
private bool Finished()
{
    // or implement any other logic to evaluate whether loop has finished
    // but thread safe
    lock (this.syncRoot)
    {
        return this.finished;
    }
} 

...

List<Task> tasks = new List<Task>();
while (this.Finished())
{
    var task = new Task(() =>
    {
        // implement your loop logic here
    })
    task.Start();
    tasks.Add(task);
}

Task.WaitAll(tasks);
2 голосов
/ 13 февраля 2012

Поскольку вы не выполняете никакой работы внутри цикла, любой пример будет надуманным. Но если вы настаиваете, вот пример, который передает идею (это будет медленнее, чем синхронная версия, потому что накладные расходы синхронизации больше, чем сама работа):

long _n;
int _i;
long _mod;

long FindModulusParallel(long n, int i)
{
    _mod = _n = n;
    _i = i;

    var actions = Enumerable.Range(0, Environment.ProcessorCount)
                            .Select<int,Action>(j => Subtract).ToArray();
    Parallel.Invoke(actions);

    return _mod;
}

void Subtract()
{
    while (Interlocked.Add(ref _n, -_i) >= 0)
        Interlocked.Add(ref _mod, -_i);
}
2 голосов
/ 13 февраля 2012

Parallel.For не может получить ссылочную переменную или Func, например, поэтому мы ограничены использованием хороших старых задач. Вот пример:

int n = 100;
int i = 3;
int accum = 0;
object logicLock = new object();
Random rand = new Random();

void Main()
{
    // No point of having more tasks than available cores.
    int maxTasks = 4;
    Task[] tasks = new Task[maxTasks];
    int count = 0;
    while(this.CheckCondition())
    {
        int index = count;
        if(count++ >= maxTasks)
        {
            Console.WriteLine("Waiting for a task slot");
            index = Task.WaitAny(tasks);
        }

        Console.WriteLine("Executing a task in slot: {0}", index);
        tasks[index] = Task.Factory.StartNew(LoopLogic);
    }

    Console.WriteLine("Done");
}

public void LoopLogic()
{
    lock(logicLock)
    {
        accum += i;
    }

    int sleepTime = rand.Next(0, 500);
    Thread.Sleep(sleepTime);
}

public bool CheckCondition()
{
    lock(logicLock) 
    {
        return (n - accum) >= i;
    }
}

Результат:

Выполнение задачи в слоте: 0
Выполнение задания в слоте: 1
Выполнение задания в слоте: 2
Выполнение задания в слоте: 3
В ожидании слота задачи
Выполнение задачи в слоте: 2
В ожидании слота задачи
Выполнение задания в слоте: 1
Ожидание слота для задачи
Выполнение задания в слоте: 3
Ожидание слота для задачи
Выполнение задания в слоте: 1
В ожидании слота задачи
Выполнение задания в слоте: 0
В ожидании слота задачи
Выполнение задания в слоте: 3
В ожидании слота задачи
Выполнение задания в слоте: 2
... больше того же самого.
Готово

...