【问题标题】:Is there anyway to end a delegate if I no longer care about the result?如果我不再关心结果,是否有办法结束委托?
【发布时间】:2013-01-30 04:10:54
【问题描述】:

我有一段代码可以搜索多个第三方 API。我根据搜索条件将搜索分为 2 组。我开始两个搜索,因为每个搜索都非常及时,但如果第一组搜索结果匹配,我不想等待第二个搜索组完成。所以基本上我所拥有的是:

Dictionary<string, string> result = null;
NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName);
IAsyncResult nameTag = nameDel.BeginInvoke(name, null, null);
if(!string.IsNullOrWhiteSpace(telNum))
{
    result = SearchByTelNum(telNum);//Will return null if a match is not found
}
if(null == result)
{
    result = nameDel.EndInvoke(nameTag);
}
//End the delegate to prevent memory leak
//else
//{
//    nameDel.EndInvoke(nameTag)
//}
return result;

所以我想在调用 SearchByTelNum 之前启动 SearchByName,以防它找不到匹配项,但是如果找到匹配项,我不想在返回匹配项之前等待 SearchByName 完成。如果我不再需要它的结果,有什么方法可以简单地结束或取消该委托?

【问题讨论】:

  • 像经理一样思考 - 不要告诉代表它的工作不再有用,让它继续并忽略它的结果。
  • 是的,我同意 D Stanley 的观点。您可以调用两个搜索并只使用第一个返回的结果。在此条件下,杀死代理可能对节省资源没有帮助。
  • 但是通过不在委托上调用 EndInvoke 是否允许可能的内存泄漏? link 供参考,它是 .NET 4.0
  • 我认为我在此处找到的 John Koerner 引用的线程中找到了我正在寻找的答案stackoverflow.com/a/1410344/1757384。通过使用 BackgroundWorker,(System.ComponentModel.BackgroundWorker) 我可以调用 CancelAsync 方法来“取消”线程。我现在正在尝试,会告诉你进展如何。

标签: c# multithreading delegates


【解决方案1】:

我能够使用 System.ComponentModel.BackgroundWorker 解决我的问题。我不一定按照预期的方式使用它,但它能够做我需要的事情。所以基本上我的新代码是这样的:

Dictionary<string, string> telResult = null,
                           nameResult = null;

BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => nameResult = SearchByName(name, bw);
bw.RunWorkerAsync();

if(!string.IsNullOrWhiteSpace(telNum))
    telResult = SearchByTelNum(telNum);//Will return null if a match is not found

if(telResult != null)
{
    bw.CancelAsync;
    return telResult;
}

bool hasTimedOut = false;
int i = timeOutCount;
while (bw.IsBusy && !hasTimedOut)
{
    System.Threading.Thread.Sleep(500);
    if (0 == --i) hasTimedOut = true;
}

return nameResult;

为了确保没有错误,我必须确保 SearchByName 定期检查 bw.CancellationPending 是否等于 true,并在这种情况下结束该方法。 CancelAsync 不会结束工作线程,它只是提醒工作线程调用者线程已取消它。

我也可以简单地使用

while(bw.IsBusy) System.Threading.Thread.Sleep(500)

等待方法完成,但如果 SearchByName 发生了一些不好的事情,你最终可能会在无限循环中永远等待。这样,我可以在方法被认为已超时并且调用者线程继续正常运行之前设置一段时间。在这种情况下,由于我每 0.5 秒检查一次 bw.IsBusy,超时长度等于 timeOutCount / 2 秒。

好的,我想我已经彻底回答了我自己的问题。

【讨论】:

    【解决方案2】:

    我已经通过定义一个可中止的参数对象来处理这个问题

    public class AbortableParameter<T>
    {
        public T Parameter { get; private set }
        public bool ShouldAbort { get; set; }
        public AbortableParameter(T parameter)
        {
            Parameter = parameter;
            ShouldAbort = false;
        }
    }
    

    只需使用您要传递给委托的任何参数创建此类的实例并保留对它的引用;如果委托应该退出,则将其设置为 true。然后,代理需要定期检查ShouldAbort,并在变为true 时优雅退出。

    这是不利的一面,委托必须定期检查,否则它是否应该中止都无关紧要。

    也可以让ShouldAbort 属性的 set 方法在设置为 true 时杀死委托,但这不是一个优雅的退出,在大多数情况下应该避免 - 但它确实有好处需要委托投票。

    【讨论】:

      猜你喜欢
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      • 2021-03-15
      • 2012-06-26
      相关资源
      最近更新 更多