"剪切"有效地排序多个线程的作业列表

时间:2018-04-26 09:57:57

标签: c# multithreading list linq sorting

我有一个List,其中包含多个Mesh - 对象。这就是这样一个网格类的样子:

public class Mesh
{
    public int GridWidth { get; }
    public int GridHeight { get; }
    public List<File> Files { get; }
    /* ... */
}

网格对象内的List个文件包含File - 对象主要由一个字符串组成,该字符串包含文件系统 - 文件路径和一个二维数组,用于保存文件内容解析后。

public class File
{
    public string Path { get; }
    public double[][] Matrix { get; set; }
    /* ... */
}

多线程和解析工作正常。我决定启动尽可能多的线程,因为我的CPU有单核。就我而言:4。

在Linq的帮助下,我首先将所有文件对象集中在一个自己的List中:

List<File> allFiles = meshes.SelectMany(mesh => mesh.Files).ToList();

之后,每个Thread从此列表中获取1/4对象并开始解析文件。

这是我的问题:相同大小的文件位于同一网格内(GridWidth * GridHeight =已解析的矩阵单元格数)。此时,可能偶然发生一个线程只获得具有较大大小的文件而另一个线程仅获取较小大小的文件。在这种情况下,一个线程会比其他线程更早完成 - 我不想要那个,因为这样效率很低。

所以我有想法首先根据它们的大小对网格列表进行排序,之后将它们的文件添加到剪切排序方法(或 Snake Sort )中)每个线程的新列表。以下算法有效。但我认为他们可能会有一些改进的空间。

这些是我的问题:这个算法是否已经足够有效,或者是否存在为每个线程提供文件列表的更好方法?如果没有更好的方式我会对更聪明的&#34;编码方式(对于所有的if / else和modulo操作,for循环似乎有点复杂)。

int cores = 4;
List<File>[] filesOfThreads = new List<Slice>[cores];

List<File> allFilesDesc = meshes.OrderByDescending(mesh => mesh.GridWidth * mesh.GridHeight).SelectMany(mesh => mesh.Files).ToList();

int threadIndex = 0;
/*
 * Inside this for-loop the threadIndex changes
 * with each cycle in this way (in case of 4 cores):
 * 0->1->2->3->3->2->1->0->0->1->2->3->3->2 ...
 * With each cycle a file of the current position of 
 * allFilesDesc[i] is added to the list of
 * filesOfThreads[threadIndex]. In this "shear" sort
 * way every thread should get approximately the same
 * number of big and small files.
 */
for (int i = 0; i < allFilesDesc.Count; i++)
{
    if (i < cores)
    {
        filesOfThreads[threadIndex] = new List<File>();
    }
    filesOfThreads[threadIndex].Add(allFilesDesc[i]);
    if (i < cores - 1)
    {
        threadIndex++;
    }
    else if ((i + 1) % cores != 0)
    {
        threadIndex += ((i + 1) / cores) % 2 == 0 ? 1 : -1;
    }
}

foreach (var files in filesOfThreads)
{
    Thread thread = new Thread(() => ComputeFiles(files));
    thread.Start();
}

1 个答案:

答案 0 :(得分:1)

我的建议

/// <summary>
/// Helper methods for the lists.
/// </summary>
public static class ListExtensions
{
public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
{
    return source
        .Select((x, i) => new { Index = i, Value = x })
        .GroupBy(x => x.Index / chunkSize)
        .Select(x => x.Select(v => v.Value).ToList())
        .ToList();
}
}

例如,如果您按照每个块的5个项目清除18个项目的列表,它会为您提供4个子列表的列表,其中包含以下项目:5-5-5-3。