多线程异步调用

6

我的Silverlight应用程序的一部分需要来自三个服务请求的数据。迄今为止,我一直在链接这些请求,以便一个完成后另一个开始……直到链的末尾,我才对数据进行必要的处理。

现在,我知道这不是最好的方法(!)。我一直在研究AutoResetEvent(MSDN示例链接)来线程化并同步结果,但无法似乎无法与异步服务调用配合使用。

是否有人怀疑这种方法或者这应该可以工作?非常感谢提供代码示例!

2个回答

7

看这个例子:

一旦两个服务都返回,将触发“已完成”事件并将“完成”打印到调试输出。关键是等待AutoResetEvents发生在后台线程中。


public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        Completed += (s, a) => { Debug.WriteLine("done"); };

        wrk.DoWork += (s, a) =>
            {
                Start();
            };

        wrk.RunWorkerAsync();
    }
    public event EventHandler Completed;

    private void Start()
    {
        auto1.WaitOne();
        auto2.WaitOne();

        Completed(this, EventArgs.Empty);
    }

    public AutoResetEvent auto1 = new AutoResetEvent(false);
    public AutoResetEvent auto2 = new AutoResetEvent(false);

    BackgroundWorker wrk = new BackgroundWorker();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ServiceReference1.Service1Client clien = new SilverlightAsyncTest.ServiceReference1.Service1Client();

        clien.DoWorkCompleted += new EventHandler<SilverlightAsyncTest.ServiceReference1.DoWorkCompletedEventArgs>(clien_DoWorkCompleted);
        clien.DoWork2Completed += new EventHandler<SilverlightAsyncTest.ServiceReference1.DoWork2CompletedEventArgs>(clien_DoWork2Completed);

        clien.DoWorkAsync();
        clien.DoWork2Async();
    }

    void clien_DoWork2Completed(object sender, SilverlightAsyncTest.ServiceReference1.DoWork2CompletedEventArgs e)
    {
        Debug.WriteLine("2");
        auto1.Set();
    }

    void clien_DoWorkCompleted(object sender, SilverlightAsyncTest.ServiceReference1.DoWorkCompletedEventArgs e)
    {
        Debug.WriteLine("1");
        auto2.Set();
    }
}

问题。你有一个auto1用于DoWork2。如果你有3个异步调用,你会只添加auto3并将其设置在DoWork3Completed事件中吗? - H20rider

3

使用每个异步方法返回的IAsyncResult中的WaitHandle可以完成此操作。

这段代码很简单。在Silverlight中,我只需进行10个服务调用,将项目添加到ListBox中。等待所有服务调用结束后,在列表中添加另一条消息(必须在不阻塞UI的情况下在不同的线程中运行)。还要注意,通过Dispatcher添加项目,因为它们会修改UI。有一堆lambda表达式,但很容易理解。

 public MainPage()
        {
            InitializeComponent();
            var results = new ObservableCollection<string>();
            var asyncResults = new List<IAsyncResult>();
            resultsList.ItemsSource = results;
            var service = new Service1Client() as Service1;

            1.To(10).Do(i=>
                asyncResults.Add(service.BeginDoWork(ar =>
                    Dispatcher.BeginInvoke(() => results.Add(String.Format("Call {0} finished: {1}", i, service.EndDoWork(ar)))),
                    null))
            );

            new Thread(()=>
            {
                asyncResults.ForEach(a => a.AsyncWaitHandle.WaitOne());
                Dispatcher.BeginInvoke(() => results.Add("Everything finished"));
            }).Start();
        }

为了帮助测试,这是该服务。

public class Service1
    {
        private const int maxMilliSecs = 500;
        private const int minMillisSecs = 100;
        [OperationContract]
        public int DoWork()
        {
            int millisSecsToWait = new Random().Next(maxMilliSecs - minMillisSecs) + minMillisSecs;
            Thread.Sleep(millisSecsToWait);
            return millisSecsToWait;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接