控制台应用程序中的异步操作?

时间:2016-11-16 09:07:57

标签: c# asynchronous

我在C#中编程。我的问题是: 在控制台应用程序中使用异步操作是否有任何意义(如果有任何示例?)

让我解释一下。假设我正在编写一个Windows应用程序(带按钮和其他小部件..)在这种情况下,将显示主窗口,然后程序将等待事件对吗? (用户按下按钮,用户执行此操作或等等)。如果用户什么都不做,那么应用程序只是在那里等待(但我认为不使用CPU)

相反,在执行控制台应用程序时,程序启动并执行一些操作,可能从用户进程事物中接收一些输入并最终确定。

现在,考虑同步和异步操作。假设我想做一些操作,当这个操作完成时,做一些其他事情。这在Windows应用程序中是有意义的。例如,用户按下按钮,程序异步启动操作,但不等待它完成。按钮操作完成。

稍后当操作完成时,它会调用其他一些函数并执行它必须执行的操作。在这两者之间没有等待或阻止。

但是如果我在控制台应用程序中做同样的事情呢?如果我调用异步操作,我必须在某处使用ManualResetEvent来阻止它,以便主函数不能正确完成?但是如果我阻止它,那么操作的异步性是没有意义的,是吗?

甚至在控制台应用程序中使用异步操作吗?

2 个答案:

答案 0 :(得分:2)

作为可以从async / await中受益的控制台应用程序的示例,请考虑需要从远程网站获取某些数据的要求。

您希望尽快获取数据,并且可以从多个网站获取数据。因此,您可以通过异步尝试同时从多个Web站点获取数据来实现此目的,但只使用最快速返回的数据(并忽略其他数据)。

这方面的一个例子是从互联网服务器获取当前时间。

这是一个完整的可编辑控制台应用程序,可以执行此操作:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine(GetTime().Result);
        }

        public static async Task<DateTime> GetTime()
        {
            return await Task.WhenAny
            (
                Task.Run(() => GetNetworkTime("time.windows.com")),
                Task.Run(() => GetNetworkTime("1.uk.pool.ntp.org")),
                Task.Run(() => GetNetworkTime("time.nist.gov"))
            ).Result;
        }

        public static async Task<DateTime> GetNetworkTime(string ntpServer)
        {
            IPAddress[] address = Dns.GetHostEntry(ntpServer).AddressList;

            if (address == null || address.Length == 0)
                throw new ArgumentException("Could not resolve ip address from '" + ntpServer + "'.", nameof(ntpServer));

            IPEndPoint ep = new IPEndPoint(address[0], 123);
            var result = await GetNetworkTime(ep);

            return result;
        }

        public static async Task<DateTime> GetNetworkTime(IPEndPoint ep)
        {
            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, ep, null);

                byte[] ntpData = new byte[48]; // RFC 2030 
                ntpData[0] = 0x1B;

                await Task.Factory.FromAsync(
                    socket.BeginSend(ntpData, 0, ntpData.Length, SocketFlags.None, null, null),
                    socket.EndSend);

                await Task.Factory.FromAsync(
                    socket.BeginReceive(ntpData, 0, ntpData.Length, SocketFlags.None, null, null),
                    socket.EndReceive);

                return asDateTime(ntpData);
            }
        }

        static DateTime asDateTime(byte[] ntpData)
        {
            byte offsetTransmitTime = 40;
            ulong intpart = 0;
            ulong fractpart = 0;

            for (int i = 0; i <= 3; i++)
                intpart = 256*intpart + ntpData[offsetTransmitTime + i];

            for (int i = 4; i <= 7; i++)
                fractpart = 256*fractpart + ntpData[offsetTransmitTime + i];

            ulong milliseconds = (intpart*1000 + (fractpart*1000)/0x100000000L);

            TimeSpan timeSpan = TimeSpan.FromTicks((long) milliseconds*TimeSpan.TicksPerMillisecond);

            DateTime dateTime = new DateTime(1900, 1, 1);
            dateTime += timeSpan;

            TimeSpan offsetAmount = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
            DateTime networkDateTime = (dateTime + offsetAmount);

            return networkDateTime;
        }
    }
}

答案 1 :(得分:0)

  

在这种情况下,将显示主窗口,然后程序将等待事件吗?

但这与asynchronus编程无关。这是一个简单的观察者模式。你班上的一个功能/空虚是&#34;听&#34;提出一个事件。组件(Button,Checkbox)引发事件(Button.Click,Checkbox.CheckedChanged)。

  

同步和异步操作

     

例如,用户按下按钮,程序异步启动操作,但不等待它完成。按钮操作完成。

你必须区别对待:同步操作是这个函数/子签名之后的所有东西:

<accessability> <return-type> <name>(<parameter>) {}

像:

public void DoSomething(int parameter1, string parameter2)
{
    Console.WriteLine(parameter1);
    Console.WriteLine(parameter2);
}

异步操作如下:

<accessability> async <return-type> <name>(<parameter>) {}

其中<return type>为void(对于asynchronus事件处理程序)或Task(对于将返回void的异步子例程)或Task<T>(对于通常会返回的函数) T

所以调用这些异步标记的方法是由&#34; await&#34;完成的。它们:

private async void myObject_HandleEvent(object sender, EventArgs e)
{
    string text = await GetStringFromDataBaseAsync();
}

private Task<string> GetStringFromDataBaseAsync()
{
    string result = "";
    // Obtain value and store it in value
    return result;
}

如果考虑使用异步编程,那么查找需要很长时间才能运行的代码片段(查询数据库,I / O事务......)。这通常可以异步进行并且运行得更快。 (但请注意,不要创建race conditions)。

最后但并非最不重要:

  

甚至在控制台应用程序中使用异步操作吗?

取决于。

例如:如果要加载数据(来自数据库/本地文件系统/ ...),则可以使用async/await来加速应用程序。由于控制台应用程序未使用任何类型的UI,因此您无法使用它来改进UI。