gRPC client do not dispose Channel

混江龙づ霸主 提交于 2021-01-27 16:08:07

问题


I'm developing .net core 2.0 application with gRPC and find out a problem: after delete reference to instance of my gRPC client class, there still channel that use resourses (memory and processor). Example code:

public class MyClient : ClientBase
    {
        public MyClient(Channel channel) : base(channel)
        {
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var list = new List<MyClient>();
            for (var i = 0; i < 10000; i++)
            {
                Console.WriteLine($"Creating {i} instance");
                list.Add(new MyClient(new Channel("127.0.0.1:61783", ChannelCredentials.Insecure)));
            }

            Console.WriteLine("press enter to list = null");
            Console.ReadLine();
            list = null;

            Console.WriteLine("press enter to GC.Collect();");
            Console.ReadLine();
            GC.Collect();

            Console.WriteLine("press enter to exit");
            Console.ReadLine();
        }
    }

If u run example, u'll see that 10% (on my PC) used by this application. Even after list = null and GC.Collect()

The reason i suppose is ClientBase do not call Channel.ShutdownAsync().

So the question is:

What is the better way to resolve problem?

p.s. actually i use a "generated by the protocol buffer compiler" Client

Client: Grpc.Core.ClientBase<TDto>

and i can't explicitly change finalizer in generated class


回答1:


Possible suggestion would be to make the client implement IDisposable and in the Dispose method call the Channel.ShutdownAsync().

public class MyClass : Client, IDisposable {
    Channel channel;
    private bool _isDisposed = false;
    private readonly object _lock = new object();

    public MyClass(Channel channel)
        : base(channel) {
        this.channel = channel;
        this.channelDisposing += onDisposing;
    }

    public Channel Channel { get { return channel; } }

    private event EventHandler channelDisposing = delegate { };

    async void onDisposing(object sender, EventArgs e) {
        await channel.ShutdownAsync();
        channel = null;
    }

    public void Dispose() {
        if (!_isDisposed) {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

    void Dispose(bool disposing) {
        // No exception should ever be thrown except in critical scenarios.
        // Unhandled exceptions during finalization will tear down the process.
        if (!_isDisposed) {
            try {
                if (disposing) {
                    // Acquire a lock on the object while disposing.
                    if (channel != null) {
                        lock (_lock) {
                            if (channel != null) {
                                channelDisposing(this, EventArgs.Empty);
                            }
                        }
                    }
                }
            } finally {
                // Ensure that the flag is set
                _isDisposed = true;
            }
        }
    }
}

This will allow you to now call Dispose on the clients and release resources or wrap them in using so that it will be done for you when they go out of scope.

public class Program {
    public static void Main(string[] args) {
        var list = new List<MyClient>();
        for (var i = 0; i < 10000; i++) {
            Console.WriteLine($"Creating {i} instance");
            list.Add(new MyClient(new Channel("127.0.0.1:61783", ChannelCredentials.Insecure)));
        }

        Console.WriteLine("press enter to dispose clients");
        Console.ReadLine();
        list.ForEach(c => c.Dispose());

        Console.WriteLine("press enter to list = null");
        Console.ReadLine();
        list = null;

        Console.WriteLine("press enter to GC.Collect();");
        Console.ReadLine();
        GC.Collect();

        Console.WriteLine("press enter to exit");
        Console.ReadLine();
    }
}


来源:https://stackoverflow.com/questions/47594441/grpc-client-do-not-dispose-channel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!