Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何暂停创建新线程,直到旧线程结束 背景_C#_Multithreading_File_Asynchronous - Fatal编程技术网

C# 如何暂停创建新线程,直到旧线程结束 背景

C# 如何暂停创建新线程,直到旧线程结束 背景,c#,multithreading,file,asynchronous,C#,Multithreading,File,Asynchronous,我有一个非常大的二进制数据文件(20+GB),需要解析、处理数据,然后编写输出。我很少有处理如此大量数据的经验,虽然我在概念化如何处理数据方面有点困难,但我确实有一个想法。注意:输入数据包含许多从IBM大型机检索到的记录,因此其格式如下: 每条记录(行/行)的前4个字节是RDW(记录描述符字)。RDW包含记录的长度(包括RDW)。由于RDWs,即使文件是一个恒定的字节流,我也知道每个记录的结束位置。我可以将这个二进制文件转换为文本文件,将每两个字节转换为其十六进制表示形式,并在记录的末尾包含一个

我有一个非常大的二进制数据文件(20+GB),需要解析、处理数据,然后编写输出。我很少有处理如此大量数据的经验,虽然我在概念化如何处理数据方面有点困难,但我确实有一个想法。注意:输入数据包含许多从IBM大型机检索到的记录,因此其格式如下:

每条记录(行/行)的前4个字节是RDW(记录描述符字)。RDW包含记录的长度(包括RDW)。由于RDWs,即使文件是一个恒定的字节流,我也知道每个记录的结束位置。我可以将这个二进制文件转换为文本文件,将每两个字节转换为其十六进制表示形式,并在记录的末尾包含一个新行字符,但如果这样翻译,恐怕一个20+GB的二进制文件会有多大

因为我想将该文件保留为二进制文件,所以我有一个方法:

  • 使用一个“主”线程按顺序读取文件
  • 一旦主线程到达记录的末尾(使用RDW中找到的信息),它就会生成一个新的“工作线程”,将从文件中读取的数据传递给该线程。
    • 工作线程解析数据,处理数据,并将其输出到某处。(我想我将把数据存储在SQLite数据库中。)
  • 当工作线程工作时,主线程继续读取文件,当它完成读取另一条记录时,它生成第二个工作线程来处理第二条记录。这将一直持续到处理完所有记录为止
  • 问题 不幸的是,我预见到了一个问题。读取“主”线程的速度将比它生成的线程快得多,我担心会创建太多线程。为了防止这种情况,我设想了以下解决方案(伪代码):

    record=file.ReadRecord()
    if(运行线程数<最大线程数)
    SpawnWorkerThread(记录);
    其他的
    Waitill(运行线程数<最大线程数)
    
    但是,我不知道如何实现这样的功能,尤其是最后的
    else
    条件。我不熟悉多线程和异步,我甚至不知道这两个术语之间的区别是什么


    有人能给我指出正确的方向吗?

    我相信您正在寻找信号灯(或者信号灯LIM可能也适用于您)。信号量“限制可以同时访问资源或资源池的线程数”。该信号量是使用特定数量的插槽创建的。然后,您可以调用“WaitOne”来等待可用的插槽,并在使用完插槽后调用“Release”。如果没有可用的插槽,“WaitOne”可以永远等待,或者直到超时发生

    因此,在您的情况下,主线程将调用WaitOne来等待可用的插槽。然后,在辅助线程的末尾,您可以调用Release来释放一个插槽

    .NET信号量:

    .NET信号量LIM(轻型信号量):
    解决方案1:

    使用。设置,哪个

    设置可同时处于活动状态的对线程池的请求数。在线程池线程可用之前,所有超过该数目的请求都将保持排队状态

    比如:

    System.Threading.ThreadPool.SetMaxThreads(50, 1000);
    // inside loop
    ThreadPool.QueueUserWorkItem(ProcessRequest);
    // end loop
    
    其中,
    ProcessRequest
    是执行此工作的方法

    解决方案2:

    如果您知道记录数:使用
    Parallel.For
    并相应地设置
    maxdegreeofpparallelism

    Parallel.For(0, 1000, new ParallelOptions { MaxDegreeOfParallelism = 10 },
    i => { 
        ProcessRequest(i);
    });
    

    这听起来正是我要找的!非常感谢你!在我阅读了更多关于信号量和信号量lim的内容之前,我将暂缓将此标记为答案。@jdcac,这正是您所要求的,但它不是解决您问题的最佳方案。创建和销毁线程是有成本的,如果您为文件中的每个记录创建和销毁一个线程,那么该成本可能会超过您想要支付的成本。如果您希望同时运行的线程不超过N个,那么您的程序应该先创建N个线程,然后重新使用它们。这就是线程池为您所做的(请参见User270576的回答)。我不太熟悉线程池的工作原理,但据我所知,它并不适用于长时间运行的任务—这里可能是这样,也可能不是这样。我的第二个想法是,如果主线程比工作线程快得多,那么一次可以排队多少线程。我不确定队列或它所能容纳的资源是否有任何限制。为什么不让您的“主”线程将数据放入队列中呢。具有一组工作线程,每个工作线程从队列中提取。您必须确保队列是同步的,这样两个工作线程就不会将相同的数据出列。Parallel.ForEach也可能是一个不需要知道记录数的选项,只要它们可以创建一个枚举器逐个记录读取记录。@wiz true!
    Parallel.For(0, 1000, new ParallelOptions { MaxDegreeOfParallelism = 10 },
    i => { 
        ProcessRequest(i);
    });