Есть ли способ изменить то, как Parallel.Foreach чередует массив, на котором он работает? - PullRequest
0 голосов
/ 22 сентября 2018

Я использую Parallel.Foreach для работы с большим массивом, где каждый элемент массива соответствует строке в растровом изображении.Однако Parallel.Foreach, по-видимому, выделяет фиксированное количество потоков, скажем, 6 потоков, и дает 1/6 массива первому потоку и 1/6 массива следующему потоку по порядку.пример:

[0]=>thread1, [1]=>thread1, [2]=>thread1, [3]=>thread1

[4]=>thread2, [5]=>thread2, [6]=>thread2, [7]=>thread2,

.. and so forth

enter image description here

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

[0]=>thread1 [1]=>thread2 [2]=>thread3 [4]=>thread4, [5]=>thread1, [6]=>thread2, etc...

есть ли способ изменить шаблон чередования, который Parallel.Foreach назначает каждому параллельному потоку, активно выполняющемуся?

Я пытаюсь получить изображение для рендеринга, используячересстрочный рисунок gif вместо того, чтобы строки растрового изображения отображались последовательно в 6 различных строках на изображении, которые заполняются вниз ...

using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;

//…

void button_click() {
    Task.Run(() =>{
        start_task();
    });
}

int ds_height=600;
public bool start_task()
{
    var cpu75 = Convert.ToInt32(Math.Ceiling((
           Environment.ProcessorCount * 0.75) * 1.0));
    //MandelInit();

    int[] ytmp;

    int version = 2;
    if (version == 1) {
        ytmp = MandelYLace();
    }
    else {
        int[] ytmp = new int[ds_height];
        for(int i=0; i < ds_height; i++)
        {
            ytmp[i] = i;
        }
        Parallel.ForEach(
            ytmp, //ylace,
            new ParallelOptions { MaxDegreeOfParallelism = cpu75 },
            yy => {
                //ybuff[yy] = MandelLine(yy);
                //ydone.Enqueue(yy);
            }
        );
        stop = true;
        return true;
}

// Interlace Y-Lines using GIF Interlaced method
int[] MandelYLace()
{
    var ylace = new int[ds_height];
    for (int y = 0, yg=0, yy=0; y < ds_height; y++)
    {
        ylace[y] = yy;

        if (yg == 0 || yg == 1)
            yy += 8;
        else if (yg == 2)
            yy += 4;
        else if (yg == 3)
            yy += 2;

        if (yy >= ds_height)
        {
            yg = (yg + 1) % 4;
            if (yg == 1) yy = 4;
            else if (yg == 2) yy = 2;
            else if (yg == 3) yy = 1; 
            else if (yg == 0) yy = 0; 
        }
    }

    return ylace;
}

1 Ответ

0 голосов
/ 22 сентября 2018

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

Решение кода: enter image description here

int ds_height=600;

public bool start_task()
{
    var cpu75 = Convert.ToInt32(Math.Ceiling((
           Environment.ProcessorCount * 0.75) * 1.0));

    var partitioner = new InterlacePartitioner(ds_height);

    Parallel.ForEach(
            partitioner,
            new ParallelOptions { MaxDegreeOfParallelism = cpu75 },
            yy => {
                //ybuff[yy] = MandelLine(yy);
                //ydone.Enqueue(yy);
            }
    );
    stop = true;
    return true;
}

Пользовательский разделитель PLINQ, использующий общий IEnumerator для реализации чередования строк в стиле gif:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Collections;

namespace NetMandelbrot
{
    // This is both the Interlaced Line IEnumerator and IEnumerable 
public class ImageInterlace : 
     IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable
{
    int[] Lines;
    int Pos;

    public ImageInterlace(int ImageHeight)
    {
        Pos = -1;
        Lines = GetLines(ImageHeight);
    }

    // Interlace Y-Lines using GIF Interlaced method
    int[] GetLines(int ImageHeight)
    {
        var ylace = new int[ImageHeight];
        for (int y = 0, yg = 0, yy = 0; y < ImageHeight; y++)
        {
            ylace[y] = yy;

            if (yg == 0 || yg == 1)
                yy += 8;
            else if (yg == 2)
                yy += 4;
            else if (yg == 3)
                yy += 2;

            if (yy >= ImageHeight)
            {
                yg = (yg + 1) % 4;
                if (yg == 1) yy = 4;
                else if (yg == 2) yy = 2;
                else if (yg == 3) yy = 1;
                else if (yg == 0) yy = 0;
            }
        }
        return ylace;
    }

    #region Implementation of IDisposable

    public void Dispose()
    {
    }

    #endregion

    #region Implementation of IEnumerable<int>
    public IEnumerator<int> GetEnumerator()
    {
        return this;
    }
    #endregion

    // Legacy C#
    #region Implementation of IEnumerable
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this;
    }
    #endregion

    #region Implementation of IEnumerator<int>
    public bool MoveNext()
    {
        bool done;
        lock (Lines)
        {
            if (Pos < Lines.Length)
            {
                Pos++;
            }
            done = (Pos < Lines.Length);
        }
        return done;
    }

    public void Reset()
    {
        lock (Lines)
        {
            Pos = -1;
        }
    }

    public int Current
    {
        get
        {
            int nextline;
            lock (Lines)
            {
                if (Pos >= Lines.Length)
                {
                    nextline = -1;
                }
                else
                {
                    nextline = Lines[Pos];
                }
            }
            return nextline;
        }
    }

    // C# Legeacy
    object IEnumerator.Current
    {
        get { return Current; }
    }

    #endregion
}

public class InterlacePartitioner : Partitioner<int>
{
    int ImageHeight = 0;
    ImageInterlace imageinterlace;

    public InterlacePartitioner(int imageHeight)
    {
        ImageHeight = imageHeight;
        imageinterlace = new ImageInterlace(ImageHeight);
    }

    public override IList<IEnumerator<int>> GetPartitions(int partitionCount)
    {
        int i = 0;

        List<List<int>> partz = new List<List<int>>();

        foreach (var yline in imageinterlace)
        {
            partz[i % partitionCount].Add(yline);
            i++;
        }
        return (IList<IEnumerator<int>>)partz;
    }

    public override IEnumerable<int> GetDynamicPartitions()
    {
        return imageinterlace;
    }

    // Not consumable from Parallel.ForEach.
    public override bool SupportsDynamicPartitions
    {
        get
        {
            return true;
        }
    }
} //end of class

}
...