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

5

最近我一直在努力学习 .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个回答

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。


0

我认为这是一个非常有效的练习,即使仅此而已。我也正在开发一个异步“委托”处理程序。您可以增加灵活性,并且将学习有关异步模型的许多知识。

我知道这个SO问题中包含一些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;
}

0

我认为你的异步方法并没有增加任何价值,因此最好让客户端决定是否异步调用你的方法。


这只是一个例子。忽略实际的实现(诚然看起来很愚蠢和无意义),我在询问如何使用委托及其IAsyncResult。 - BFree
因为提供了同步和异步版本,客户端仍然可以做出决定。OP更关心选择的方法是否是实现APM的好方法。 - Crippledsmurf
-1 没有人可以假设异步方法是否会为 OP 的假想库提供任何附加值。 - IAbstract

0

这并没有什么问题,但似乎有点毫无意义。

实际上,您正在实现Facade模式,但并没有简化接口。根据您的具体情况,最好添加自己的类来简化使用AsyncCallback和IAsyncResult,以使调用更准确地反映在您的类中使用的属性。


我没有看到 OP 所做的事情与定义 Facade 模式的要点之间的相似之处。 - IAbstract

0
我个人更喜欢使用事件来通知异步进程何时结束,如果该类旨在被另一个库使用,则使用AsyncOperation类和SendOrPostCallback委托确保事件在调用者线程上引发,以不干扰UI。 但是,如果异步操作要在同一程序集中执行,我更喜欢调用代码定义如何进行异步调用。

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