代码之家  ›  专栏  ›  技术社区  ›  devios1

线程。中止和替换

  •  4
  • devios1  · 技术社区  · 14 年前

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

    如果线程真的是可中止的,我们可以简单地让一个线程基于上一次更改的搜索字符串运行,并取消任何正在进行的线程。

    现在普遍接受的最佳实践是使用延迟计时器作为用户类型,在启动操作之前等待0.5到1秒。我希望很明显这不是一个 理想的 从理论上讲,解决方案(任何一种人为延迟都会造成一个无法克服的人为瓶颈,即使只有0.5秒)。

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

    一个(unideal)解决方法是让多个操作同时执行,假定这样做是安全的,但这仍然会导致性能显著降低。

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

    干杯。

    4 回复  |  直到 14 年前
        1
  •  3
  •   Rusty    14 年前

    Parallel Programming 就像 TPL cancellation 正如马克·拜尔斯所说。“永不中止线程!除非你确切地知道自己在做什么……即便如此,也不要这么做。”谢天谢地,这条规则已经放松了。

    另一个允许更多“组合”方法的工具是 Reactive Extensions for .NET (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
  •  4
  •   Mark Byers    14 年前

    你应该看一看 Task Parallel Library 在.NET4和新的 cancellation model . 任务可以并发运行,可以安全地取消它们。它看起来很适合你的需要。

        3
  •  2
  •   Jon Skeet    14 年前

    这只在你控制任务的时候有效-或者当它已经被编程来做这件事的时候-但是在很多情况下它是有用的。

    一般同意“等待上一个操作完成后再执行下一个操作”。当然,这取决于手术,但是如果你 并行运行两个操作,可以防止第一个操作的完成把事情弄糟,并且不介意第一个操作继续运行,直到它注意到您刚才按照这个答案的第一段设置的“stop please”标志,这很好。不过,这在很大程度上取决于形势。

        4
  •  1
  •   Jon B    14 年前

    Thread.Abort() 并不意味着你不能在后台线程中取消一个操作。

    // set to true to cancel
    volatile bool cancel;
    
    // background thread function
    void foo()
    {
        bool done = false;
    
        while (!done && !cancel)
        {
            ...
        }
    }
    

    诀窍是让你的背景线程退出 ,并不意外。