繁体   English   中英

在TPL任务中包装.NET Remoting异步方法

[英]Wrap .NET Remoting async method in TPL Task

我们有一个基于.NET Remoting的传统应用程序。 我们的客户端客户端库目前仅支持同步操作。 我想用基于TPL的async Task<>方法添加异步操作。

作为概念证明,我已经基于这些指令的修改版本设置了基本的远程服务器/客户端解决方案。

我还发现这篇文章描述了如何将基于APM的异步操作转换为基于TPL的异步任务(使用Task.Factory.FromAsync

我不确定的是我是否被迫在.BeginInvoke()指定回调函数,以及指定.EndInvoke() 如果两者都是必需的,回调函数和.EndInvoke()之间究竟有什么区别。 如果只需要一个,我应该使用哪一个来返回值,并确保我没有内存泄漏

这是我当前的代码,我没有将回调传递给.BeginInvoke()

public class Client : MarshalByRefObject
{
    private IServiceClass service;

    public delegate double TimeConsumingCallDelegate();

    public void Configure()
    {
        RemotingConfiguration.Configure("client.exe.config", false);

        var wellKnownClientTypeEntry = RemotingConfiguration.GetRegisteredWellKnownClientTypes()
            .Single(wct => wct.ObjectType.Equals(typeof(IServiceClass)));

        this.service = Activator.GetObject(typeof(IServiceClass), wellKnownClientTypeEntry.ObjectUrl) as IServiceClass;
    }

    public async Task<double> RemoteTimeConsumingRemoteCall()
    {
        var timeConsumingCallDelegate = new TimeConsumingCallDelegate(service.TimeConsumingRemoteCall);

        return await Task.Factory.FromAsync
            (
                timeConsumingCallDelegate.BeginInvoke(null, null),
                timeConsumingCallDelegate.EndInvoke
           );
    }

    public async Task RunAsync()
    {
        var result = await RemoteTimeConsumingRemoteCall();
        Console.WriteLine($"Result of TPL remote call: {result} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
    }
}

public class Program
{
    public static async Task Main(string[] Args)
    {
        Client clientApp = new Client();
        clientApp.Configure();

        await clientApp.RunAsync();

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey(false);
    }
}

回调函数和.EndInvoke()之间的区别在于回调将在来自线程.EndInvoke()的任意线程上执行。 如果必须确保从与调用BeginInvoke的线程相同的线程上获取读取结果,则不应使用回调,而是轮询IAsyncResult对象并在操作完成时调用.EndInvoke()

如果调用.EndInvoke()之后.Beginnvoke()您阻塞线程,直到操作完成。 这将有效,但会扩展得很差。

所以,你做的似乎没事!

出于效率原因,您必须指定回调函数。 如果FromAsync仅具有要使用的IAsyncResult ,则在异步结果完成时无法通知它。 它必须使用一个事件来等待。 这会阻塞一个线程(或者,它注册一个线程池等待可能不是那么糟糕)。

高效的异步IO需要在某种程度上进行回调。

如果您要进行异步,我假设您正在执行此操作,因为您有许多并发呼叫或者呼叫的运行时间非常长。 因此,您应该使用更有效的机制。

如果你没有很多或长时间运行的调用,那么async不会以任何方式帮助你提高性能,但它仍然可以使GUI编程更容易。

所以这不正确:

public async Task<double> RemoteTimeConsumingRemoteCall()
{
    var timeConsumingCallDelegate = new TimeConsumingCallDelegate(service.TimeConsumingRemoteCall);

    return await Task.Factory.FromAsync
        (
            timeConsumingCallDelegate.BeginInvoke(null, null),
            timeConsumingCallDelegate.EndInvoke
       );
}

为了确保您的实现确实不阻止任何线程,我会这样做:在服务器端插入一个Thread.Sleep(100000)并在客户端上发出1000个并发调用。 您应该发现线程数不会增加。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM