如何正确并行化工作人员任务? - c#

请考虑以下代码片段,并注意设置numberTasksToSpinOff等于1,然后等于3,4或更大(取决于计算机上的线程资源)之间的总运行时间差异。当完成更多任务时,我注意到运行时间更长。

我特意将数据收集传递到每个工作人员任务同时读取的每个工作人员实例中。我认为只要这些操作只是读取或枚举,任务就可以访问共享数据结构而不会阻塞。

我的目标是剥离多个任务,这些任务通过读取操作在同一个共享数据结构上进行迭代,并在大约同一时间完全完成,而无论任务数量如何。

编辑:请参阅第二个代码片段,其中我实现了Parallel.Foreach()并创建每个工作人员自己的数据集,因此无法通过不同的任务/线程访问相同的数据结构。但是我仍然看到不可接受的开销。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"Entry Main Function Thread Id: {Thread.CurrentThread.ManagedThreadId}");

        //run
        var task = Task.Run(async () =>
        {
            Console.WriteLine($"Entry RunMe Task Thread Id: {Thread.CurrentThread.ManagedThreadId}");
            await RunMe();

            Console.WriteLine($"Exit RunMe Task Thread Id: {Thread.CurrentThread.ManagedThreadId}");
        });

        task.Wait();

        Console.WriteLine($"Exit Main Function Thread Id: {Thread.CurrentThread.ManagedThreadId}");

        Console.WriteLine("Press key to quit");
        Console.ReadLine();
    }

    private static async Task RunMe()
    {
        var watch = new Stopwatch();
        var numberTasksToSpinOff = 6;
        var numberItems = 20000;
        var random = new Random((int)DateTime.Now.Ticks);
        var dataPoints = Enumerable.Range(1, numberItems).Select(x => random.NextDouble()).ToList();
        var tasks = new List<Task>();
        var workers = new List<Worker>();

        //structure workers
        for (int i = 1; i <= numberTasksToSpinOff; i++)
        {
            workers.Add(new Worker(i, dataPoints));
        }

        //start timer
        watch.Restart();

        //spin off tasks
        foreach (var worker in workers)
        {
            tasks.Add(Task.Run(() =>
            {
                Console.WriteLine($"Entry WorkerId: {worker.WorkerId} -> New Tasks spun off with in Thread Id: {Thread.CurrentThread.ManagedThreadId}");
                worker.DoSomeWork();
                Console.WriteLine($"Exit WorkerId: {worker.WorkerId} -> New Tasks spun off with in Thread Id: {Thread.CurrentThread.ManagedThreadId}");
            }));

        }

        //completion tasks
        await Task.WhenAll(tasks);

        //stop timer
        watch.Stop();

        Console.WriteLine($"Time it took to complete in Milliseconds: {watch.ElapsedMilliseconds}");
    }
}

public class Worker
{
    public int WorkerId { get; set; }
    private List<double> _data;

    public Worker(int workerId, List<double> data)
    {
        WorkerId = workerId;
        _data = data;
    }

    public void DoSomeWork()
    {
        var indexPos = 0;

        foreach (var dp in _data)
        {
            var subSet = _data.Skip(indexPos).Take(_data.Count - indexPos).ToList();
            indexPos++;
        }
    }
}

第二个代码段:

class Program
{
    static void Main(string[] args)
    {
        var watch = new Stopwatch();
        var numberTasksToSpinOff = 1;
        var numberItems = 20000;
        //var random = new Random((int)DateTime.Now.Ticks);
        //var dataPoints = Enumerable.Range(1, numberItems).Select(x => random.NextDouble()).ToList();
        var workers = new List<Worker>();

        //structure workers
        for (int i = 1; i <= numberTasksToSpinOff; i++)
        {
            workers.Add(new Worker(i));
        }

        //start timer
        watch.Restart();

        //parellel work

        if (workers.Any())
        {
            var processorCount = Environment.ProcessorCount;
            var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = processorCount };
            Parallel.ForEach(workers, parallelOptions, DoSomeWork);
        }

        //stop timer
        watch.Stop();
        Console.WriteLine($"Time it took to complete in Milliseconds: {watch.ElapsedMilliseconds}");

        Console.WriteLine("Press key to quit");
        Console.ReadLine();
    }

    private static void DoSomeWork(Worker worker)
    {
        Console.WriteLine($"WorkerId: {worker.WorkerId} -> New Tasks spun off with in Thread Id: {Thread.CurrentThread.ManagedThreadId}");

        var indexPos = 0;

        foreach (var dp in worker.Data)
        {
            var subSet = worker.Data.Skip(indexPos).Take(worker.Data.Count - indexPos).ToList();
            indexPos++;
        }
    }
}

public class Worker
{
    public int WorkerId { get; set; }
    public List<double> Data { get; set; }

    public Worker(int workerId)
    {
        WorkerId = workerId;

        var numberItems = 20000;
        var random = new Random((int)DateTime.Now.Ticks);
        Data = Enumerable.Range(1, numberItems).Select(x => random.NextDouble()).ToList();

    }
}

参考方案

注意:以下答案基于测试和观察,而不是基于definitiv的知识。

分拆的任务越多,生成的开销就越大,因此总的执行时间也会增加。但是,如果您从另一个角度考虑它,您将看到实际处理的“数据点”将增加您启动的更多任务(直到达到可用硬件线程的限制):

以下值是在我的计算机(4C / 8T)上以每个列表10000点生成的:

1名工人-> 1891毫秒-> 5288 p / s
2名工作人员-> 1921毫秒-> 10411 p / s
4名工作人员-> 2670毫秒-> 14981 p / s
8名工作人员-> 4871毫秒-> 16423 p / s
12名工作人员-> 7449毫秒-> 16109 p / s

在那里,您看到直到达到“核心限制”为止,处理后的数据显着增加,然后直到达到“线程限制”为止,它的增加仍然很明显,但是之后又减少了,因为开销增加了,没有可用的硬件了-资源。

使用javascript在客户端的列表视图中选择所有复选框 - javascript

我有一个列表视图,在标题中有一个复选框。如果标题复选框已选中/未选中,我想选择行中的所有复选框。如何在客户端实现此目标?这是ListView设计代码。<asp:ListView ID="lvTypes" runat="server" GroupPlaceholderID="groupPlaceHolde…

Ajax表单未获得结果 - javascript

我有一个带有搜索功能的主页。从主页搜索可以正常工作,但是当我尝试使用ajax表单(在url.com/search?id=biology上)再次搜索时,我被重定向到404页面,提示未找到/Search。主页上的表格:@using (Html.BeginForm("Index", "Search", new { Retur…

使用php echo定义一个javascript var - javascript

我已经看到了对该问题的多个答复-因此,我敢肯定有人会很快将其标记为重复,但是我在任何其他线程中都没有看到该特定问题的答案。我有两个测试文件:a.php和a.js在a.php中,我定义$q = $_GET['q']; 效果很好。然后,我调用一个单独的a.js文件,其中有:var partNumber = " <?php ec…

使用数组填充动态下拉列表 - php

我正在尝试使用多维数组在PHP中进行动态下拉列表。我的第一个选择框正确填充,但是在选择建筑物时,我需要第二个选择框来显示用于第一个选择的相应显示(大厅,休息室等)这是数组:$displays = array( "Company" => array( "Building 1"=>array( "Di…

调整窗口大小时如何调整YouTube播放器的大小 - php

我想显示包含YouTube视频的弹出窗口。我的问题是当用户调整弹出窗口的大小时如何调整YouTube播放器的大小?弹出窗口的头部分PHP / HTML代码<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/…