繁体   English   中英

我应该以这种方式使用ConcurrentQueue还是单个线程

[英]Should I use a ConcurrentQueue this way or individual threads

我正在做的事情相当于赞美的邮件合并,然后将文件转换为PDF ...基于.Net 4.5,我看到了几种执行线程处理的方法。 使用线程安全队列的线程似乎很有趣(计划A),但是我可以看到一个潜在的问题。 你怎么看? 我将尽力而为,但请输入需要的内容。

这样做的前提是,与PDF转换相比,数据库处理将花费更多的时间。

在这两种情况下,每个文件的数据库处理都是在其自己的线程/任务中完成的,但是PDF转换可以在许多单线程/任务中完成(方案B),也可以在一个长期运行的线程中完成(方案A) 。 我想知道的是PDF转换。 它全部在try / catch语句中,但该线程一定不能失败或全部失败(计划A)。 您认为这是个好主意吗? 任何建议,将不胜感激。

/* A class to process a file: */ 
public class c_FileToConvert
{
    public string InFileName { get; set; }
    public int FileProcessingState { get; set; }
    public string ErrorMessage { get; set; }
    public List<string> listData = null;
    c_FileToConvert(string inFileName)
    {
        InFileName = inFileName;
        FileProcessingState = 0;
        ErrorMessage = ""; // yah, yah, yah - String.Empty
        listData = new List<string>();
    }   
    public void doDbProcessing()
    {
        // get the data from database and put strings in this.listData
        DAL.getDataForFile(this.InFileName, this.ErrorMessage); // static function
        if(this.ErrorMessage != "")
            this.FileProcessingState = -1; //fatal error
        else // Open file and append strings to it
        {  
            foreach(string s in this.listData}
                ...
            FileProcessingState = 1; // enum DB_WORK_COMPLETE ...
         }
    }   
    public void doPDFProcessing()
    {
        PDFConverter cPDFConverter = new PDFConverter();
        cPDFConverter.convertToPDF(InFileName, InFileName + ".PDF");
        FileProcessingState = 2; // enum PDF_WORK_COMPLETE ...
    }       
}

/*** These only for Plan A ***/
public ConcurrentQueue<c_FileToConvert> ConncurrentQueueFiles = new ConcurrentQueue<c_FileToConvert>(); 
public bool bProcessPDFs;   

public void doProcessing() // This is the main thread of the Windows Service 
{
    List<c_FileToConvert> listcFileToConvert = new List<c_FileToConvert>();

    /*** Only for Plan A ***/
    bProcessPDFs = true;
    Task task1 = new Task(new Action(startProcessingPDFs)); // Start it and forget it
    task1.Start();

    while(1 == 1)
    {
        List<string> listFileNamesToProcess = new List<string>();
        DAL.getFileNamesToProcessFromDb(listFileNamesToProcess);

        foreach(string s in listFileNamesToProcess)
        {
            c_FileToConvert cFileToConvert = new c_FileToConvert(s);
            listcFileToConvert.Add(cFileToConvert);
        }       

        foreach(c_FileToConvert c in listcFileToConvert)
            if(c.FileProcessingState == 0)
                Thread t = new Thread(new ParameterizedThreadStart(c.doDbProcessing));

        /** This is Plan A - throw it on single long running PDF processing thread **/
        foreach(c_FileToConvert c in listcFileToConvert)
            if(c.FileProcessingState == 1)
                ConncurrentQueueFiles.Enqueue(c);

        /*** This is Plan B - traditional thread for each file conversion ***/              
        foreach(c_FileToConvert c in listcFileToConvert)
            if(c.FileProcessingState == 1)
                Thread t = new Thread(new ParameterizedThreadStart(c.doPDFProcessing));

        int iCount = 0;
        for(int iCount = 0; iCount < c_FileToConvert.Count; iCount++;)
        {
            if((c.FileProcessingState == -1) || (c.FileProcessingState == 2))
            {
                DAL.updateProcessingState(c.FileProcessingState)
                listcFileToConvert.RemoveAt(iCount);
            }
        }
        sleep(1000);
    }
}   
public void startProcessingPDFs() /*** Only for Plan A ***/
{
    while (bProcessPDFs == true)
    {
        if (ConncurrentQueueFiles.IsEmpty == false)
        {
            try
            {
            c_FileToConvert cFileToConvert = null;
            if (ConncurrentQueueFiles.TryDequeue(out cFileToConvert) == true)
                cFileToConvert.doPDFProcessing();
            }
            catch(Exception e)
            {
                cFileToConvert.FileProcessingState = -1;
                cFileToConvert.ErrorMessage = e.message;
            }
        }
    }
}

计划A似乎是一个不错的解决方案,但是如果任务以某种方式失败,该怎么办? 是的,PDF转换可以通过单个线程完成,但是我想将它们保留给数据库处理。

这是用文本编辑器编写的,是我能做到的最简单的代码,因此可能有些问题,但我想我已经明白了。

您正在处理多少个文件? 10点 十万? 如果数量很大,则使用1个线程来运行每个文件的数据库查询不是一个好主意。

线程是一种非常底层的控制流结构,我建议您在应用程序代码中尽量避免产生很多混乱且详细的线程,包括生成,联接,同步等。 如果可以的话,保持它愚蠢的简单。

怎么样:将每个文件所需的数据放入线程安全队列中。 创建另一个线程安全队列以获取结果。 生成一些线程,这些线程反复从输入队列中提取项目,运行查询,转换为PDF,然后将输出推入输出队列。 除了输入和输出队列外,线程绝对不应共享任何内容。

您可以选择任意数量的工作线程,也可以尝试看看有多少个工作线程。 不要为每个文件创建一个线程-只需选择一个数字即可获得良好的CPU和磁盘利用率。

或者,如果您的语言/图书馆有并行的地图运算符,请使用该运算符。 这将节省您很多麻烦。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM