繁体   English   中英

如何异步调用静态方法

[英]How to Asynchronously Call Static Methods

我正在尝试构造一个简单的类,该类根据要重新启动的计算机类型调用重新启动功能。 被调用的方法是指包含公共静态方法的库。 我想使用Task异步调用这些静态方法,以并行调用重新启动方法。 这是到目前为止的代码:

编辑根据社区的要求,这是同一个问题的版本,下面的代码正在编译。 请不要因为您需要Renci.SshNet库,而且还需要在项目中设置对该库的引用。

// libs
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;

using Renci.SshNet;



namespace ConsoleApp
{
    class Program
    {


        // Simple Host class
        public class CHost
        {
            public string IP;
            public string HostType;

            public CHost(string inType, string inIP)
            {// constructor
                this.IP         = inIP;
                this.HostType   = inType;
            }
        }



        // Call test function
        static void Main(string[] args)
        {

            // Create a set of hosts
            var HostList = new List<CHost>();
            HostList.Add( new CHost("Machine1", "10.52.0.93"));
            HostList.Add( new CHost("Machine1", "10.52.0.30"));
            HostList.Add( new CHost("Machine2", "10.52.0.34"));


            // Call async host reboot call
            RebootMachines(HostList);
        }




        // Reboot method
        public static async void RebootMachines(List<CHost> iHosts)
        {
            // Locals
            var tasks = new List<Task>();


            // Build list of Reboot calls - as a List of Tasks
            foreach(var host in iHosts)
            {

                if (host.HostType == "Machine1")
                {// machine type 1
                    var task = CallRestartMachine1(host.IP);
                    tasks.Add(task);    // Add task to task list
                }
                else if (host.HostType == "Machine2")
                {// machine type 2
                    var task = CallRestartMachine2(host.IP);
                    tasks.Add(task);    // Add task to task list
                }   
            }


            // Run all tasks in task list in parallel
            await Task.WhenAll(tasks);
        }



        // ASYNC METHODS until here
        private static async Task CallRestartMachine1(string host)
        {// helper method: reboot machines of type 1

            // The compiler complains here (RebootByWritingAFile is a static method)
            // Error: "This methods lacks await operators and will run synchronously..."
            RebootByWritingAFile(@"D:\RebootMe.bm","reboot");

        }
        private static async Task CallRestartMachine2(string host)
        {// helper method: reboot machines of type 2

            // The compiler warns here (RebootByWritingAFile is a static method)
            // Error: "This methods lacks await operators and will run synchronously..."
            RebootByNetwork(host,"user","pwd");

        }




        // STATIC METHODS here, going forward
        private static void RebootByWritingAFile(string inPath, string inText)
        {// This method does a lot of checks using more static methods, but then only writes a file


            try
            {
                File.WriteAllText(inPath, inText); // static m
            }
            catch
            {
                // do nothing for now
            }
        }
        private static void RebootByNetwork(string host, string user, string pass)
        {
            // Locals
            string rawASIC = "";
            SshClient SSHclient;
            SshCommand SSHcmd;


            // Send reboot command to linux machine
            try
            {
                SSHclient = new SshClient(host, 22, user, pass);
                SSHclient.Connect();
                SSHcmd = SSHclient.RunCommand("exec /sbin/reboot");
                rawASIC = SSHcmd.Result.ToString();
                SSHclient.Disconnect();
                SSHclient.Dispose();
            }
            catch
            {
                // do nothing for now
            }
        }




    }
}

到目前为止,我与此设置有关的唯一问题是,静态方法会立即(顺序)调用,而不是分配给任务。 例如线

        ...
        else if (host.HostType == "Machine2")
        {// machine type 2
            var task = CallRestartMachine2(host.IP);
            tasks.Add(task);    // Add task to task list
        }  
        ...

如果主机不可访问,则需要20秒才能执行。 如果无法访问10个主机,则顺序持续时间为20 * 10 = 200秒。

我知道一些看似相似的问题,例如

但是,引用的lambda表达式仍然给我带来相同的编译器错误[“此方法缺少await运算符...”]。 另外,如果重启集群中的大量计算机,由于高开销,我也不想产生显式线程(新Thread(()=> ...))。

我可能需要重新启动群集中的大量计算机。 因此,我的问题是: 如何更改构造以能够并行调用上述静态方法

编辑由于@JohanP和@MickyD的评论,我想详细说明一下我实际上已经尝试编写两种静态方法的异步版本。 但是,这使我陷入困境,每次在async方法中调用静态方法时,我都会收到编译器警告,该调用将是同步的。 这是一个示例,说明我如何尝试将对方法的调用包装为异步任务,希望以异步方式调用相关方法。

private static async Task CallRestartMachine1(string host)
{// helper method: reboot machines of type 1

    // in this version, compiler underlines '=>' and states that 
    // method is still called synchronously
    var test = await Task.Run(async () =>
    {
        RebootByWritingAFile(host);
    });

}

有没有办法包装静态方法调用,使所有静态子方法都不需要全部重写为异步方法?

谢谢大家。

您的代码将async与延续混合在一起,并且甚至无法编译。 您需要使它一直处于async 当您调用RebootMachines(...)并且无法await该呼叫时,可以在该时间表上安排继续,即RebootMachines(...).ContinueWith(t=> Console.WriteLine('All Done'))

public static async Task RebootMachines(List<CHost> iHosts)
{
    var tasks = new List<Task>();

    // Build list of Reboot calls - as a List of Tasks
    foreach(var host in iHosts)
    {
        if (host.HostType == "Machine1")
        {// machine type 1
             task = CallRestartMachine1(host.IP);
        }
        else if (host.HostType == "Machine2")
        {// machine type 2
            task = CallRestartMachine2(host.IP);
        }

         // Add task to task list - for subsequent parallel processing
         tasks.Add(task);
    }


    // Run all tasks in task list in parallel
    await Task.WhenAll(tasks);
}

private static async Task CallRestartMachine1(string host)
{// helper method: reboot machines of type 1

    //RebootByWritingAFile is method that returns a Task, you need to await it
    // that is why the compiler is warning you
    await RebootByWritingAFile(host);

}

private static async Task CallRestartMachine2(string host)
{// helper method: reboot machines of type 2

    await RebootByNetwork(host);

}

大家,谢谢您的投入和帮助。 在过去的几天里,我一直在和他玩耍,并提出了以下方法来异步调用静态方法:

// libs
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;

using Renci.SshNet;



namespace ConsoleApp
{
    class Program
    {


        // Simple Host class
        public class CHost
        {
            public string IP;
            public string HostType;

            public CHost(string inType, string inIP)
            {// constructor
                this.IP         = inIP;
                this.HostType   = inType;
            }
        }



        // Call test function
        static void Main(string[] args)
        {

            // Create a set of hosts
            var HostList = new List<CHost>();
            HostList.Add( new CHost("Machine1", "10.52.0.93"));
            HostList.Add( new CHost("Machine1", "10.52.0.30"));
            HostList.Add( new CHost("Machine2", "10.52.0.34"));


            // Call async host reboot call
            RebootMachines(HostList);
        }




        // Reboot method
        public static async void RebootMachines(List<CHost> iHosts)
        {
            // Locals
            var tasks = new List<Task>();


            // Build list of Reboot calls - as a List of Tasks
            foreach(var host in iHosts)
            {

                if (host.HostType == "Machine1")
                {// machine type 1
                     var task = CallRestartMachine1(host.IP);
                    tasks.Add(task);    // Add task to task list
                }
                else if (host.HostType == "Machine2")
                {// machine type 2
                    var task = CallRestartMachine2(host.IP);
                    tasks.Add(task);    // Add task to task list
                }   
            }


            // Run all tasks in task list in parallel
            await Task.WhenAll(tasks);
        }



        // ASYNC METHODS until here
        private static async Task CallRestartMachine1(string host)
        {// helper method: reboot machines of type 1

            await Task.Run(() =>
            {
                RebootByWritingAFile(@"D:\RebootMe.bm", "reboot");
            });

        }
        private static async Task CallRestartMachine2(string host)
        {// helper method: reboot machines of type 2

            await Task.Run(() =>
            {
                RebootByNetwork(host, "user", "pwd");
            });

        }




        // STATIC METHODS here, going forward
        private static void RebootByWritingAFile(string inPath, string inText)
        {// This method does a lot of checks using more static methods, but then only writes a file


            try
            {
                File.WriteAllText(inPath, inText); // static m
            }
            catch
            {
                // do nothing for now
            }
        }
        private static void RebootByNetwork(string host, string user, string pass)
        {
            // Locals
            string rawASIC = "";
            SshClient SSHclient;
            SshCommand SSHcmd;


            // Send reboot command to linux machine
            try
            {
                SSHclient = new SshClient(host, 22, user, pass);
                SSHclient.Connect();
                SSHcmd = SSHclient.RunCommand("exec /sbin/reboot");
                rawASIC = SSHcmd.Result.ToString();
                SSHclient.Disconnect();
                SSHclient.Dispose();
            }
            catch
            {
                // do nothing for now
            }
        }




    }
}

此设置异步调用我的静态方法。 我希望这对遇到类似问题的人有所帮助。 再次感谢您的所有意见。

我认为您应该重新考虑线程的“高开销”:与每个RPC调用的网络往返次数和等待时间相比,IMHO的开销可以忽略不计。 我非常确定,创建N个线程所需的资源与运行N个网络请求(无论是http [s],RPC还是其他)所需的资源相比是微不足道的。

我的方法是将任务排入一个线程安全的集合( ConcurrentQueueConcurrentBag和好友),然后生成有限数量的线程循环通过这些工作项,直到该集合为空并结束。

这不仅可以让您并行运行任务,还可以以受控的并行方式运行它们。

暂无
暂无

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

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