C# 如何确保Task.Factory.StartNew不会';你不能放慢主线的速度吗?

C# 如何确保Task.Factory.StartNew不会';你不能放慢主线的速度吗?,c#,concurrency,task-parallel-library,taskfactory,C#,Concurrency,Task Parallel Library,Taskfactory,有一堆压缩数据块必须异步压缩-,而不以任何形式阻塞或减慢主线程 解压后的块将在解压后立即被主线程使用 目前我是这样做的: foreach (var chunkPair in compressedChunkData) { var task = Task.Factory.StartNew<Chunk>(() => { var compressedBytes = Convert.FromBase64Str

有一堆压缩数据块必须异步压缩-,而不以任何形式阻塞或减慢主线程

解压后的块将在解压后立即被主线程使用

目前我是这样做的:

foreach (var chunkPair in compressedChunkData)
{                        
    var task = Task.Factory.StartNew<Chunk>(() =>
    {
        var compressedBytes = Convert.FromBase64String(chunkPair.Value);
        var chunk = Decompress(compressedBytes);
        return chunk;
    }).ContinueWith((finishedTask) =>
    {
        var chunk = finishedTask.Result;
        TaskFinishActions.Enqueue(() =>
        {
            chunk.PostSerialize();
            document.Chunks.Add(chunkPair.Key, chunk);
        });
    });
}
// By the time we get here 20ms has passed!!!
<代码>foreach(压缩dchunkData中的var chunkPair) { var task=task.Factory.StartNew(()=> { var compressedBytes=Convert.FromBase64String(chunkPair.Value); var chunk=解压缩(压缩字节); 返回块; }).继续((完成任务)=> { var chunk=finishedTask.Result; TaskFinishActions.Enqueue(()=> { chunk.PostSerialize(); document.Chunks.Add(chunkPair.Key,chunk); }); }); } //当我们到达这里的时候,20毫秒已经过去了!!! 问题是,这似乎劫持了主线程运行的核心,这破坏了性能

有没有办法让
TaskFactory
仅在主线程被阻塞的短暂时间内,每个核心都有线程,并且上下文切换远离主线程

编辑:foreach循环并不是代码中唯一变慢的部分,只要有相当数量的解压缩任务在运行,主线程就会显著变慢

EDIT2:要解压缩的新数据始终到达,循环不仅运行一次:

  • 假设有250个项目首先到达
    compressedChunkData
  • 下一帧你有10个项目,下一个12,下一个0,下一个2,等等

您是否担心for循环速度变慢或循环后面的代码运行缓慢

如果您担心for循环,那么有一个简单的解决方案,在任何情况下都应该遵循。您可以提供的实例来控制并发程度

Parallel.ForEach(compressedChunkData, chunkPair => {
    var compressedBytes = Convert.FromBase64String(chunkPair.Value);
    var chunk = Decompress(compressedBytes);
    TaskFinishActions.Enqueue(() => {
        chunk.PostSerialize();
        document.Chunks.Add(chunkPair.Key, chunk);
    });
});
如果您担心循环后代码的速度会变慢,请查看。本质上,您应该使用
async
wait
来完成此任务,或者在单独的任务上启动
Parallel.Foreach

编辑:

首先让我们弄清楚:在像windows这样的操作系统上,没有为线程或进程保留CPU这样的事情。它在时间片调度上工作)。因此,即使解压线程可能不会阻塞主线程,它也可能由于其他进程上CPU密集型活动而被阻塞。将我们的偏好传达给操作系统的方法是使用优先级和CPU相关性

还有其他方法需要更多的手动控制,因此需要更多的工作

  • 也许您应该有一个单独的解压过程,并使用进程优先级和CPU亲和力来告诉操作系统它想处理哪些内核
  • 您可以创建一个调度程序类来管理RequestQueue()。每个解压缩请求都应该在单个线程上进行管理(该线程将分配给单个逻辑CPU)。确保调度程序使用的CPU不超过(总CPU-1)(为主线程保留一个可用)

  • 您可以使用自定义的
    TaskScheduler
    ,将线程优先级设置为较低的值。Windows总是先安排优先级较高的线程

    也许你需要为任务设定一个截止日期,这样他们就不会排得太多。听起来您需要低延迟处理。每个任务都可以检查其第一个操作是否在N秒前计划,如果是,则立即退出


    另一种设计是生产者/消费者场景,低优先级线程承担工作。考虑到您的需求,我认为没有必要这样做,但这是一个更灵活的解决方案。创建数百个任务不是问题。每个任务只是内存中的一个小数据结构。任务!=线程。

    您可以为您的问题设置尽可能高的主线程优先级。您正在运行一个
    forach
    ,该循环的20ms不是正常且明显的吗?foreach循环不是问题,它有260个项目。4核。Rene Vogt,TaskcreationOptions.LongRunning只会让情况变得更糟,因为这意味着创建的线程可能比需要的多。创建260个任务并不理想。如果需要并行性,我会使用单个任务或
    任务。运行(()=>Parallel.ForEach(…)
    。Charles Mager,是的,这似乎工作得更好。Parallel.ForEach块。这是不能接受的。即使您将它放在Task.Run(()=>Parallel.ForEach(…)中,也只有在您有一组固定的压缩数据时,它才能解决问题。如果要解压缩的新数据总是一个接一个地到达,而您仍然需要为每个数据创建新任务,该怎么办?这种方法根本不起作用。我必须说,如果您只需要对压缩的Chunkdata进行一次检查,而不是每一帧/迭代,Task.Run(()=>Parallel.ForEach(…)的效果会更好。@jbeur您是否尝试过使用async/await。我将以另一种方式更新答案