【问题标题】:BackgroundWorker Blocking Issue - Inconsistency between Integration Test and Real AppBackgroundWorker 阻塞问题 - 集成测试和真实应用程序之间的不一致
【发布时间】:2014-05-13 14:23:16
【问题描述】:

我遇到了一个奇怪的情况。我正在尝试使用 BackgroundWorker 实例的列表,对它们调用 RunWorkerAsync() ,然后等待它们全部完成,然后再向调用者返回响应。当我从一个 NUnit 集成测试中调用该方法时,这运行良好,该测试运行了工作程序内部的所有代码。但是,当我从 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;
}

执行所有工作人员的私有方法,阻塞直到完成并处理异常:

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;
}

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    你只是在主线程上调用Thread.Sleep,所以它阻塞了。您需要使用回调或事件来解决此问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多