Thread.Abort和替代品

时间:2010-07-29 21:07:20

标签: .net performance concurrency theory parallel-processing

这更多是出于个人的好奇心/兴趣,而不是我试图解决的具体问题。

假设您有一个程序正在对用户提供的信息(例如搜索字符串)执行某些操作,该信息会随着用户的输入而更改。假设您希望向用户显示他们在任何给定时间输入的内容的最相关信息。

如果线程真的可以中断,我们可以根据最后更改的搜索字符串运行一个线程,并取消之前正在进行的所有线程。

现在普遍接受的最佳做法是在用户输入时使用延迟计时器,在开始操作之前等待.5到1秒。从理论上讲,我希望显而易见的是,这不是理想的解决方案(任何类型的人工延迟都会造成永远无法克服的人为瓶颈,即使只有0.5秒)。

此外,今天的最佳实践继续说明任何后续操作应该在执行之前等待前一个操作完成。在一个我们不能中止运营的世界里,这是有道理的,但从理论上讲,这远非理想。想象一下,用户键入一个字符并暂停足够长的时间以便开始操作。假设此操作需要10秒钟才能执行。用户现在被迫等待不可接受的时间,然后才能看到他/她的查询结果。

对此的一个(不理想的)解决方法是让多个操作同时执行,假设这样做是安全的,但这仍然会导致性能显着降低。

所以我只是想知道人们对此的看法,至少是针对.NET的,以及自从我上次研究它以后我是否应该了解这个领域是否有任何新的发展(并行库可能?)。我也很想知道是否有任何其他语言/框架可以比.NET更好地处理这种细粒度的操作控制。

干杯。

4 个答案:

答案 0 :(得分:4)

您应该查看.NET 4中的Task Parallel Library和新的cancellation model。任务可以同时运行,取消它们是安全的。它看起来非常适合您的需求。

答案 1 :(得分:3)

使用。{4}的Parallel Programming增强功能,如Mark Byers所提及的TPLcancellation。 “永远不要中止一个线程!除非你确切地知道你在做什么......即使如此也不要。”幸好感到放松了。

另一种允许采用更“组合”方法的工具是Reactive Extensions for .NET (Rx)。从项目的主页..

  

Rx是一个用于撰写的库   异步和基于事件的程序   使用可观察的集合。

他们最近发布了动手实验....

Curing the asynchronous blues with the Reactive Extensions for .NET

...包括一个解决方案,在时间的奇怪巧合下,解决你的例子...“假设你想向用户显示他们在任何给定时间输入的内容的最相关信息。” ..并且需要取消/中止/停止正在进行的任务。

来自实验室的简要介绍......

  

在我们正在运行的样本中,我们正在构建   一个简单的字典建议   应用。用户输入后   搜索词,应用程序将触发   关闭对Web服务的调用   提出建议。既然我们没有   我想要阻止用户界面   与...保持沟通   字典服务异步。

按照优秀的步骤,得到的解决方案是......

var txt = new TextBox(); 
var lst = new ListBox { Top = txt.Height + 10 }; 
var frm = new Form { 
    Controls = { txt, lst } 
}; 

// Turn the user input into a tamed sequence of strings. 
var textChanged = from evt in Observable
                  .FromEvent<EventArgs>(txt, "TextChanged") 
                  select ((TextBox)evt.Sender).Text; 

var input = textChanged 
            .Throttle(TimeSpan.FromSeconds(1)) 
            .DistinctUntilChanged(); 

// Bridge with the web service's MatchInDict method. 
var svc = new DictServiceSoapClient("DictServiceSoap"); 
var matchInDict = Observable
                  .FromAsyncPattern<string, string, string, DictionaryWord[]> 
                  (svc.BeginMatchInDict, svc.EndMatchInDict); 

Func<string, IObservable<DictionaryWord[]>> matchInWordNetByPrefix = 
    term => matchInDict("wn", term, "prefix"); 

// The grand composition connecting the user input with the web service. 
var res = from term in input 
          from word in matchInWordNetByPrefix(term).TakeUntil(input) 
          select word; 

// Synchronize with the UI thread and populate the ListBox or signal an error. 
using (res.ObserveOn(lst).Subscribe( 
    words => { 
        lst.Items.Clear(); 
        lst.Items.AddRange((from word in words select word.Word).ToArray()); 
    }, 
    ex => { 
        MessageBox.Show("An error occurred: " + ex.Message, frm.Text, 
                        MessageBoxButtons.OK, MessageBoxIcon.Error); 
    })) 
{ 
    Application.Run(frm); 
} // Proper disposal happens upon exiting the application. 

享受。

答案 2 :(得分:2)

基本上,中止任务的干净方法是很好地问它,然后让它自己优雅地关闭。这可能是一个标志,一个取消令牌(例如Parallel Extensions)或类似的东西。

这只适用于您控制任务的时间 - 或者当它已经编程完成时 - 但它在很多情况下都很有用。

同意“在执行下一个操作之前等待上一个操作完成”。当然这取决于操作 - 但是如果你可以并行运行两个操作,可以防止第一个操作完成,并且不介意第一个继续运行直到它注意到你刚刚按照这个答案的第一段设置的“停止请”标志,那很好。这在很大程度上取决于情况。

答案 3 :(得分:1)

仅仅因为你不应该滥用Thread.Abort()并不意味着你无法取消后台线程中的操作。

// set to true to cancel
volatile bool cancel;

// background thread function
void foo()
{
    bool done = false;

    while (!done && !cancel)
    {
        ...
    }
}

诀窍是让你的后台线程干净地退出 ,而不是意外。