如何在 C# 中多线程执行长期任务
How to multithread long going task in C#
我有问题。我有应用程序,可以生成带有报告服务的 pdf。它工作正常,但需要大约 20-60 秒。生成一个pdf。这次是报告服务内部错误的结果。当我通过网络需要一个 pdf,或者一晚上需要 300 个 pdf 时,没关系,但现在我需要生成 7278 个文件。在一个线程中大约需要 4 天(大约 96 小时)。我需要让它在一晚(8-12 小时)内运行。我在考虑多线程。
关于代码。 Long 运行 任务(生成 pdf)在特殊的 Web 服务中生成,由控制台应用程序执行。控制台应用程序,首先获取客户端列表 (clientsId) 和报告结束日期。
代码:
DateTime batchDate = new DateTime(year, month, 1).GetEndOfMonthDate();
int[] clientsId = GetClientsIds(batchDate);
SaveLogFile(batchDate);
LogProcessingStart(clientsId);
int successedCount = 0;
int processingCount = 1;
CreateReportsDirectoryIfNecessary(ReportDir);
int i = 0;
while (i < clientsId.Length)
{
try
{
logger.Trace(string.Format("Przetwarzanie klient_id = {0}. {1}/{2}", clientsId[i], processingCount, clientsId.Length));
ExecuteRequest(batchDate, clientsId[i]);
logger.Trace(string.Format("Koniec przetwarzania klient_id = {0}", clientsId[i]));
successedCount++;
}
catch (SoapException ex)
{
logger.Trace(string.Format("Błąd przetwarzania klient id = {0}.", clientsId[i]));
logger.Trace(string.Format("Szczegóły : {0}", ex.Actor));
}
catch (Exception ex)
{
logger.Trace("Błąd " + ex.Message);
}
i++;
processingCount++;
Thread.Sleep(TaskDelaySeconds * 1000);
}
protected override void ExecuteRequest(DateTime batchDate, int clientId)
{
bool success = false;
for (int i = 0; i < 10 && success == false; i++)
{
try
{
var result = gateway.GetPlatformReport(clientId, batchDate);
string reportPath = ReportDir + "/" + result.ReportName + ".pdf";
File.WriteAllBytes(reportPath, result.Report);
success = true;
}
catch (Exception ex)
{
string origAssemblyLocation = Assembly.GetExecutingAssembly().CodeBase;
logger.Trace("Błąd generowania raportu. Szczegóły " + ex.Message);
logger.Trace(string.Format("Próbuje jeszcze raz.. (Retry = {0})", i + 1));
}
}
}
长 运行 任务(生成 pdf)在执行 "gateway.GetPlatformReport(clientId, batchDate)" 的 ExecuteRequest(batchDate, clientsId[i]) 中生成(执行 Web 服务并需要 20-60 秒,每个客户端要求)。控制台应用程序和网络服务都在同一台机器上。
目前我有7278个客户,整个过程需要4天。
您可以尝试用并发 for 循环替换 while 循环。
Parallel.For(0, clientsId.Length, i =>
{
// While body.
});
有关详细信息,请参阅:https://msdn.microsoft.com/en-us/library/Ff963552.aspx and https://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.for%28v=vs.110%29.aspx
看看Parallel.For。此构造类似于 for 循环,但会自动处理工作负载的分区和 运行 多个线程上的代码。
Parallel.For(0, clientsId.Length, i => ExecuteRequest(batchDate, clientsId[i]));
在客户端中使用 Parallel.For
对您没有帮助,除非 Web 服务可以同时处理多个请求。确保 Web 服务 运行 在多个线程上有多个请求,然后您可以按照其他人的建议在您的客户端中使用 Parallel.For。
也就是说,我会查看 PDF 生成代码。每个文件60秒很多,也许你可以加快速度。
更新:另一种选择
如果您的 Web 服务已经处理并发调用,则根本不需要更改客户端应用程序 - 只需 运行 控制台应用程序的多个实例,并为每个实例提供一组不同的项目。
我有问题。我有应用程序,可以生成带有报告服务的 pdf。它工作正常,但需要大约 20-60 秒。生成一个pdf。这次是报告服务内部错误的结果。当我通过网络需要一个 pdf,或者一晚上需要 300 个 pdf 时,没关系,但现在我需要生成 7278 个文件。在一个线程中大约需要 4 天(大约 96 小时)。我需要让它在一晚(8-12 小时)内运行。我在考虑多线程。
关于代码。 Long 运行 任务(生成 pdf)在特殊的 Web 服务中生成,由控制台应用程序执行。控制台应用程序,首先获取客户端列表 (clientsId) 和报告结束日期。
代码:
DateTime batchDate = new DateTime(year, month, 1).GetEndOfMonthDate();
int[] clientsId = GetClientsIds(batchDate);
SaveLogFile(batchDate);
LogProcessingStart(clientsId);
int successedCount = 0;
int processingCount = 1;
CreateReportsDirectoryIfNecessary(ReportDir);
int i = 0;
while (i < clientsId.Length)
{
try
{
logger.Trace(string.Format("Przetwarzanie klient_id = {0}. {1}/{2}", clientsId[i], processingCount, clientsId.Length));
ExecuteRequest(batchDate, clientsId[i]);
logger.Trace(string.Format("Koniec przetwarzania klient_id = {0}", clientsId[i]));
successedCount++;
}
catch (SoapException ex)
{
logger.Trace(string.Format("Błąd przetwarzania klient id = {0}.", clientsId[i]));
logger.Trace(string.Format("Szczegóły : {0}", ex.Actor));
}
catch (Exception ex)
{
logger.Trace("Błąd " + ex.Message);
}
i++;
processingCount++;
Thread.Sleep(TaskDelaySeconds * 1000);
}
protected override void ExecuteRequest(DateTime batchDate, int clientId)
{
bool success = false;
for (int i = 0; i < 10 && success == false; i++)
{
try
{
var result = gateway.GetPlatformReport(clientId, batchDate);
string reportPath = ReportDir + "/" + result.ReportName + ".pdf";
File.WriteAllBytes(reportPath, result.Report);
success = true;
}
catch (Exception ex)
{
string origAssemblyLocation = Assembly.GetExecutingAssembly().CodeBase;
logger.Trace("Błąd generowania raportu. Szczegóły " + ex.Message);
logger.Trace(string.Format("Próbuje jeszcze raz.. (Retry = {0})", i + 1));
}
}
}
长 运行 任务(生成 pdf)在执行 "gateway.GetPlatformReport(clientId, batchDate)" 的 ExecuteRequest(batchDate, clientsId[i]) 中生成(执行 Web 服务并需要 20-60 秒,每个客户端要求)。控制台应用程序和网络服务都在同一台机器上。
目前我有7278个客户,整个过程需要4天。
您可以尝试用并发 for 循环替换 while 循环。
Parallel.For(0, clientsId.Length, i =>
{
// While body.
});
有关详细信息,请参阅:https://msdn.microsoft.com/en-us/library/Ff963552.aspx and https://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.for%28v=vs.110%29.aspx
看看Parallel.For。此构造类似于 for 循环,但会自动处理工作负载的分区和 运行 多个线程上的代码。
Parallel.For(0, clientsId.Length, i => ExecuteRequest(batchDate, clientsId[i]));
在客户端中使用 Parallel.For
对您没有帮助,除非 Web 服务可以同时处理多个请求。确保 Web 服务 运行 在多个线程上有多个请求,然后您可以按照其他人的建议在您的客户端中使用 Parallel.For。
也就是说,我会查看 PDF 生成代码。每个文件60秒很多,也许你可以加快速度。
更新:另一种选择 如果您的 Web 服务已经处理并发调用,则根本不需要更改客户端应用程序 - 只需 运行 控制台应用程序的多个实例,并为每个实例提供一组不同的项目。