BackgroundWorker阻塞问题-集成测试和实际应用之间的不一致
本文关键字:应用 之间 不一致 问题 集成测试 BackgroundWorker | 更新日期: 2023-09-27 18:03:20
我遇到了一个奇怪的情况。我试图使用BackgroundWorker实例列表,在它们上调用RunWorkerAsync(),然后等待它们全部完成,然后返回对调用者的响应。当我从NUnit集成测试中调用该方法时,它运行得很好,该测试会执行worker中的所有代码。然而,当我从我的web应用程序执行,非常相同的代码不断阻塞主线程和RunWorkerCompleted回调从未触发。为什么会这样?以下是我的代码(这里只使用1个BackgroundWorker来说明,但我只在实际使用> 1时使用它):
创建BackgroundWorkers并以阻塞方式执行它们的主代码:
// Build a list of BackgroundWorker instances representing the work needing to be done
var workers = new List<BackgroundWorker>
{
GetContactsByFullNameAsync(lastName, firstName),
};
// Execute the work to be done (blocking during execution)
this.ExecuteAsyncWork(workers);
// Aggregate up the contacts and return the final result
return this.AggregateContacts(result);
新建一个BackgroundWorker的私有函数(但不执行它):
private BackgroundWorker GetContactsByFullNameAsync(string lastName, string firstName)
{
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
var result = new SuperSearchResultDTO();
IList<Contact> contacts = _contactRepository.GetContactsByFullName(lastName, firstName);
// Transform any resulting Contact instances to ContactDTO instances
if (contacts != null && contacts.Count != 0)
contacts.ToList().ForEach(c => result.Contacts.Add(ContactDTO.GetFromContact(c)));
args.Result = result;
};
worker.RunWorkerCompleted += (sender, e) =>
{
if (e.Error != null)
// An error was thrown inside the repository, but since it was thrown in a separate thread, it
// won't stop the current thread from executing as per usual. We need to log the exception with
// the results, and handle it later. Throwing right here doesn't do anything.
_asyncWork[source] = new SuperSearchResultDTO { Exception = e.Error };
else if (e.Cancelled)
_asyncWork[source] = new SuperSearchResultDTO { Exception = new Exception("GetSSOContactsByEmailAsync was cancelled") };
else
// Cast the results from type "object" to SuperSearchResultDTO
_asyncWork[source] = (SuperSearchResultDTO)e.Result;
};
return worker;
}
私有方法,用于执行所有worker,阻塞直到完成并处理异常:
private void ExecuteAsyncWork(List<BackgroundWorker> workers)
{
// Kick of the searches against the different data sources simultaneously
workers.ForEach(x => x.RunWorkerAsync());
// BLOCK the current thread until either all the async methods are complete
while (workers.Any(x => x.IsBusy))
System.Threading.Thread.Sleep(50);
// Handle any exceptions
var exception = _asyncWork.Where(x => x.Value != null && x.Value.Exception != null).Select(x => x.Value.Exception).FirstOrDefault();
if (exception != null)
throw exception;
}
您只是在主线程上调用Thread.Sleep
,因此它会阻塞。您需要使用回调或事件来解决这个问题。