我在C#中编程。我的问题是: 在控制台应用程序中使用异步操作是否有任何意义(如果有任何示例?)
让我解释一下。假设我正在编写一个Windows应用程序(带按钮和其他小部件..)在这种情况下,将显示主窗口,然后程序将等待事件对吗? (用户按下按钮,用户执行此操作或等等)。如果用户什么都不做,那么应用程序只是在那里等待(但我认为不使用CPU)
相反,在执行控制台应用程序时,程序启动并执行一些操作,可能从用户进程事物中接收一些输入并最终确定。
现在,考虑同步和异步操作。假设我想做一些操作,当这个操作完成时,做一些其他事情。这在Windows应用程序中是有意义的。例如,用户按下按钮,程序异步启动操作,但不等待它完成。按钮操作完成。
稍后当操作完成时,它会调用其他一些函数并执行它必须执行的操作。在这两者之间没有等待或阻止。
但是如果我在控制台应用程序中做同样的事情呢?如果我调用异步操作,我必须在某处使用ManualResetEvent来阻止它,以便主函数不能正确完成?但是如果我阻止它,那么操作的异步性是没有意义的,是吗?
甚至在控制台应用程序中使用异步操作吗?
答案 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。