异步实现

时间:2009-05-16 01:02:38

标签: c# multithreading asynchronous

我正在尝试开发一个支持异步方法调用的类。这是我到目前为止所提出的,但是,我不确定它是否是“正确的方法”。

我只希望异步方法执行一次,它不必支持多次执行,因此我没有使用AsyncOperationManager类。

知道异步模式的人能否给我一些反馈?我这样做是正确的吗?

任何帮助都会受到赞赏,因为我无法找到有关单一调用异步方法的任何信息。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace ConsoleApplication1 {

    public delegate void WorkerDelegate();

    class Program {

        static void Main(string[] args) {

            String taskId = new Guid().ToString();

            AsyncTest test = new AsyncTest();
            test.DoSomethingLongAsyncCompleted += new AsyncCompletedEventHandler(test_DoSomethingLongAsyncCompleted);
            test.DoSomethingLongProgressChanged += new ProgressChangedEventHandler(test_DoSomethingLongProgressChanged);
            test.DoSomethingLongAsync(ItsOver, taskId);

            // Cancel after 2 seconds
            Thread.Sleep(2000);
            test.DoSomethingLongCancelAsync();

            Console.ReadLine(); //Pause the console window
        }

        static void test_DoSomethingLongProgressChanged(object sender, ProgressChangedEventArgs e) {
            Console.WriteLine("Percent complete: " + e.ProgressPercentage);
        }

        static void test_DoSomethingLongAsyncCompleted(object sender, AsyncCompletedEventArgs e) {
            Console.WriteLine("Cancelled? " + e.Cancelled);
            Console.WriteLine("Task ID: " + (String)e.UserState);
        }

        static void ItsOver(IAsyncResult r) {
            Console.WriteLine("Task ID: " + (String)r.AsyncState);
        }
    }

    class AsyncTest {

        IAsyncResult _asyncResult = null;
        Object _stateObj = null;
        AsyncCallback _callBackDelegate;

        public event ProgressChangedEventHandler DoSomethingLongProgressChanged;
        public event AsyncCompletedEventHandler DoSomethingLongAsyncCompleted;


        public IAsyncResult DoSomethingLongAsync(AsyncCallback userCallback, Object userState) {

            if (_stateObj != null)
                throw new InvalidOperationException("Method already started");

            WorkerDelegate worker = new WorkerDelegate(DoSomethingLong);

            _callBackDelegate = userCallback;
            _asyncResult = worker.BeginInvoke(null, userState);

            return _asyncResult;
        }

        public void DoSomethingLongCancelAsync() {
            _stateObj = null;
        }

        public void DoSomethingLong() {

            // Set state object if method was called synchronously
            if (_stateObj == null)
                _stateObj = new Object();

            for (int i = 0; i < 10; i++) {

                //If state object is null, break out of operation
                if (_stateObj == null) break;

                Thread.Sleep(1000);
                Console.WriteLine("Elapsed 1sec");

                if (DoSomethingLongProgressChanged != null) {
                    // Percentage calculation for demo only :-)
                    DoSomethingLongProgressChanged(this, new ProgressChangedEventArgs(i+1 * 10, _stateObj));
                }
            }

            // Only execute if method was called async
            if (_callBackDelegate != null) {
                _callBackDelegate(_asyncResult);

                DoSomethingLongAsyncCompleted(
                    this,
                    new AsyncCompletedEventArgs(null, (_stateObj == null), _asyncResult.AsyncState)
                );
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

有两种主要方法可以处理异步模型,请查看Asynchronous Programming Model上的这篇MSDN文章。您似乎正在尝试使用IAsyncResult技术。我倾向于仅将此用于低级系统IO操作。

对于UI或API,我倾向于使用事件模型,因为我认为它更容易处理。对于您的情况,您可以向QueueUserWorkItem发送事件,跟踪SynchronizationContext并在触发已完成的事件时使用它。 (如果您使用的是WPF,则可以使用DispatchObject。)

这是我之前使用过的一个ContactLoader类。

public class ContactLoader
{
    public List<Contact> Contacts { get; private set; }
    private readonly IRepository<Contact> contactsRepository;

    public ContactLoader(IRepository<Contact> contactsRepository)
    {
        this.contactsRepository = contactsRepository;
    }

    public event AsyncCompletedEventHandler Completed;
    public void OnCompleted(AsyncCompletedEventArgs args)
    {
        if (Completed != null)
            Completed(this, args);
    }

    public bool Cancel { get; set; }

    private SynchronizationContext _loadContext;
    public void LoadAsync(AsyncCompletedEventHandler completed)
    {
        Completed += completed;
        LoadAsync();
    }
    public void LoadAsync()
    {
        if (_loadContext != null)
            throw new InvalidOperationException("This component can only handle 1 async request at a time");

        _loadContext = SynchronizationContext.Current;

        ThreadPool.QueueUserWorkItem(new WaitCallback(_Load));
    }

    public void Load()
    {
        _Load(null);
    }

    private void _Load(object state)
    {
        Exception asyncException = null;
        try
        {
            Contacts = contactsRepository.GetAll();

            if (Cancel)
            {
                _Cancel();
                return;
            }
        }
        catch (Exception ex)
        {
            asyncException = ex;
        }

        if (_loadContext != null)
        {
            AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(asyncException, false, null);
            _loadContext.Post(args =>
            {
                OnCompleted(args as AsyncCompletedEventArgs);
            }, e);
            _loadContext = null;
        }
        else
        {
            if (asyncException != null) throw asyncException;
        }
    }

    private void _Cancel()
    {
        if (_loadContext != null)
        {
            AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(null, true, null);
            _loadContext.Post(args =>
            {
                OnCompleted(args as AsyncCompletedEventArgs);
            }, e);
            _loadContext = null;
        }
    }
}