Async 'Event-based Asynchronous Pattern' Sample

Mar 3, 2011 at 2:21 PM
Edited Mar 3, 2011 at 2:23 PM

Hi,

Would it possible for you to show a template on how an event-based asynchronous pattern works with AsynFunc?

For example, I have 3 different methods to call in any sequence continuously namely Method1( ), Method2( ) and Method3( ).

Each of the method in the queue must finish its execution first before it can proceed to the next method in the queue.

Example:                                              

Queue->. . .|Method3( )|Method2( )|Method1( ) (using FIFO)

In the above case,

Method1( ) will be executed first.

Method2( ) will be next

Method3( ) will be last and so on and so forth.

I am quite excited to see this working using AsyncFunc.

Thanks a lot and have great day!

Sid

Coordinator
May 3, 2011 at 12:32 AM

Hi Sid,

I'm terribly sorry I missed your message. I thought I've set up everything right to get all notifications through email but I was wrong.

I've prepared a small code snipped you asked me for. I made an assumption that all methods have the same signatures, thus they can be stored in the Queue<AsyncFunc<>> container and they share the same completion handler. I can imagine that you may want to use methods with different signatures. If that's the case you would need to create some kind of abstraction witch will start your AsyncFuncs (they can accept different parameters) and handle completion (they can have different types). If you are not limited by the Framework version I would suggest Task Parallel Library for scenarios where there are complex dependencies between asynchronous operations (tasks).

    class Program
    {
        static void Main(string[] args)
        {
            Queue<AsyncFunc<string>> queue = new Queue<AsyncFunc<string>>();
            queue.Enqueue(new AsyncFunc<string>(Method1));
            queue.Enqueue(new AsyncFunc<string>(Method2));
            queue.Enqueue(new AsyncFunc<string>(Method3));

            ExecuteSequentially(queue);
            Console.ReadLine();
        }

        public static void ExecuteSequentially(Queue<AsyncFunc<string>> queue)
        {
            if (queue.Count > 0)
            {
                AsyncFunc<string> func = queue.Dequeue();
                func.Completed += new AsyncFuncCompletedEventHandler<string>(HandleCompletion);
                func.Completed += (s, e) => ExecuteSequentially(queue);
                func.InvokeAsync();
            }
        }

        static void HandleCompletion(object sender, AsyncFuncCompletedEventArgs<string> e)
        {
            Console.WriteLine(e.Result);
        }

        public static string Method1()
        {
            return "Method1";
        }

        public static string Method2()
        {
            return "Method2";
        }

        public static string Method3()
        {
            return "Method3";
        }
    }

 

Coordinator
May 3, 2011 at 1:06 AM

I've been thinking about the abstraction necessary in the case with different signatures. I think I could encapsulate it in the following interface:

    public interface IAsyncFunc
    {
        bool IsBusy { get; }
        void Cancel();
        event AsyncCompletedEventHandler Completed;
        event ProgressChangedEventHandler ProgressChanged;
    }

Then AsyncFunc<> could implement it implicitly with one exception. Completed event would need to be implemented explicitly in order to avoid conflict with AsyncFuncCompletedEventHandler<TResult> Completed event. Users would be able to decide what information they need and if they want to synchronize multiple operations they would use one from IAsyncFunc. Unfortunately this would increase complexity as AsyncFunc<> would have 2 Completed events.

This approach wouldn't solve the problem of InvokeAsync method. We would need something more... I could create a workaround by extending AsyncFunc<> with InvokeInFuture. This method would save parameters which would be used in the future when one calls parameterless InvokeAsync overload present in the general interface:

    public interface IAsyncFunc
    {
        ...
        void InvokeAsync();
    }

Then users would be able to coordinate execution better. The only costs is the complexity...

I would really like to hear your opinion before I make any changes to the API :-)

Thanks,

Stan