这是实现异步编程模型的好方法吗?

时间:2010-02-07 07:06:41

标签: c# .net multithreading asynchronous

我最近一直在努力学习关于.Net多线程的一切。 (变得更好,但仍然觉得有很多东西需要学习)。现在我专注于APM(异步编程模型),这通常被称为:

//non async method
public int DoSomeWork(int arg)
{
   //do something and return result
}

//async version
public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
{

}

public int EndDoSomeWork(IAsyncResult result)
{

}

现在,假设我正在编写一些库,并且我希望将此功能公开给任何使用我的API的人,我正在考虑实现此模式的方法。实现IAsyncResult接口是可能的,但它似乎相当复杂。我的问题是,如果使用委托是一个可接受的解决方案。我的意思是:

public class MyClass
{
    private Func<int, int> func;

    //non async method
    public int DoSomeWork(int arg)
    {
        //do something and return result
    }

    //async version
    public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
    {
        this.func = new Func<int, int>(DoSomeWork);
        var asyncResult = this.func.BeginInvoke(arg,callback,object);
        return asyncResult;
    }

    public int EndDoSomeWork(IAsyncResult result)
    {
        return this.func.EndInvoke(result);
    }
}

基本上,每个代表都将BeginXxx和EndXxx功能融入其中。是不是可以利用它,只是暴露IAsyncResult,或者有什么问题,我没想到。

5 个答案:

答案 0 :(得分:1)

我认为这是实现APM的一种好方法,但目前每个实例都会出现多个异步调用错误。

为什么不直接将委托用法外部化?

我的意思是,如果您只是将实际逻辑放在课堂上,那么让任何调用您方法的人都可以:

MyClass c = new MyClass();
Func<int, int> f = c.DoSomeWork;
IAsyncResult ar1 = f.BeginInvoke(1, null, null);
IAsyncResult ar2 = f.BeginInvoke(2, null, null);
//...

我想我所倡导的甚至不是自己实施APM,而只是向那些打电话给你的方法的人推荐他们使用内置于代表中的APM。

答案 1 :(得分:0)

恕我直言,我认为您的异步方法不会添加任何值,所以只需让客户端决定它是否会异步调用您的方法。

答案 2 :(得分:0)

我认为这是一个非常有效的练习,如果没有别的。我也正在研究一个异步的'委托'处理程序。您可以增加灵活性,并且您将学习很多关于异步模型的知识。

我知道这个SO question包含一些Linq练习。但是,它可能会让您了解如何使用表达式树来使其更加健壮。我还没有深入研究这个主题,并为您提供更具体的信息。

以下是发布异步方法的旧代码示例。这是学习反思和一些有趣实现的过时练习。把它拿走它的价值,但它可以帮助你提出一些想法:

public delegate void delVoidMethod(params object[] args);

/// <summary>
/// Publishes an asynchronous method to the delegate collection.
/// </summary>
/// <param name="methodOwner">Target object owning the delegated method.</param>
/// <param name="method">The delegated method.</param>
/// <param name="callback">The method designated as a callback delegate.</param>
/// <param name="ptr">The delegated method's runtime handle.</param>
/// <returns>True if publishing was successful.</returns>
public bool PublishAsyncMethod(object target , MethodInfo method ,
    MethodInfo callback , out IntPtr ptr)
{
    try
    {
        ptr = method.MethodHandle.Value;

        delVoidMethod dMethod = (delVoidMethod)Delegate.CreateDelegate
            (typeof(delVoidMethod) , target , method);
        AsyncCallback callBack = (AsyncCallback)Delegate.CreateDelegate
             (typeof(AsyncCallback) , target , callback);

        handlers[ptr] = new DelegateStruct(dMethod , callBack);

        Logger.WriteLine("Delegate : {0}.{1} -> {2}.{3} published." ,
            method.DeclaringType.Name , method.Name ,
            callback.DeclaringType.Name , callback.Name);
        return true;
    }
    catch (ArgumentException ArgEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            ArgEx.Source , ArgEx.InnerException , ArgEx.Message);
    }
    catch (MissingMethodException BadMethEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            BadMethEx.Source , BadMethEx.InnerException , BadMethEx.Message);
    }
    catch (MethodAccessException MethAccEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            MethAccEx.Source , MethAccEx.InnerException , MethAccEx.Message);
    }

    ptr = IntPtr.Zero;

    return false;
}

答案 3 :(得分:0)

它绝对没有错,但似乎有点无意义。

您实际上是在实现Facade pattern,但不会使界面变得更简单。可能更好(取决于您的具体情况)添加您自己的类以简化使用AsyncCallback和IAsyncResult,以使调用更准确地反映您的类中使用的属性。

答案 4 :(得分:0)

我个人更喜欢使用事件在异步进程结束时通知,如果该类打算由另一个库使用,则使用AsyncOperation类和SendOrPostCallback委托来确保在调用者线程上引发事件而不会中断用户界面。 但是,如果要在同一个程序集中执行异步操作,我宁愿使用调用代码来定义如何进行异步调用。