我有一个控制台应用程序查询数据库,然后将一些记录张贴到循环中的REST API(api不支持批量发布,所以我必须循环每个记录和单独的帖子,如果相关的话)。数据库访问速度快,没有问题,根据我设置的计时器,api post循环也是如此,但是应用程序本身需要很长时间才能在完成工作后退出。控制台应用程序在完成工作后需要很长时间才能退出
在我介绍Parallel.Foreach
加速张贴后,开始发生这种情况。在使用非并行循环之前,发布1000条记录的平均时间为〜10分钟,但应用程序会在完成后立即返回并退出(如预期的那样)。使用并行循环后,根据我使用的Stopwatch
计时器,这个计时器会减少到〜44秒的平均值,但是应用程序不会退出,直到大约2分钟过去 - 在所有工作完成后约1分15秒。
该应用程序没有做任何'额外'。它输入main
,main
调用一个方法从数据库中检索一些记录(1-2秒),将1000条记录转发到另一个循环遍历它们并将每个记录发送到api的方法,然后退出。除此之外,出于某种原因,它不会立即退出。
我在调用发布方法之前立即在main
中放置了一个并在方法返回后立即记录时间,并且定时器与方法内部的定时器对齐,平均时间约为46秒。所以延迟发生在发布方法返回之后,但在main
函数退出之前,但此时没有任何定义。调试没有显示任何异常。这是一个解除分配的问题,与并行循环产生的所有对象有关吗?
无论我是否使用附加的调试程序运行,或者在为发行版构建时直接执行二进制文件(因此不是分离延迟问题),都会发生这种情况。我已经看过这样的其他SO问题,但他们的方法并没有改变。任何输入将不胜感激。
代码张贴功能:
public ProcessingState PostClockingRecordBatchParallel(List<ClockingEvent> batch, int tokenExpiryTolerance)
{
log.Info($"Attempting to post batch of {batch.Count.ToString()} clocking records to API with an auth token expiry tolerance of {tokenExpiryTolerance} seconds");
try
{
ProcessingState state = new ProcessingState() { PendingRecords = batch };
List<ClockingEvent> successfulRecords = new List<ClockingEvent>();
Stopwatch timer = new Stopwatch();
ServicePointManager.UseNagleAlgorithm = false; //Performance optimization related to RestSharp lib
authToken = Authenticate();
timer.Start();
Parallel.ForEach(state.PendingRecords, pr =>
{
successfulRecords.Add(PostClockingRecord(pr, tokenExpiryTolerance));
});
//Prior non-parallel version
//state.PendingRecords.ForEach(pr =>
//{
// successfulRecords.Add(PostClockingRecord(pr, tokenExpiryTolerance));
//});
state.PendingRecords = state.PendingRecords.Except(successfulRecords).ToList();
state.LastSuccessfulRecord = successfulRecords.OrderBy(r => r.EventID).Last().EventID;
log.Info($"PostClockingRecordBatchParallel - Time elapsed: {new TimeSpan(timer.ElapsedTicks).ToString()}");
return state;
}
catch (Exception ex)
{
log.Fatal($"Failed to post records to API (exception encountered: {ex}).");
throw;
}
}
谢谢,正是我在找的! – Hangman