dan*_*ich 415 .net c# asynchronous console-application
我是使用async修饰符进行异步编程的新手.我试图弄清楚如何确保我Main的控制台应用程序的方法实际上异步运行.
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = bs.GetList();
}
}
public class Bootstrapper {
public async Task<List<TvChannel>> GetList()
{
GetPrograms pro = new GetPrograms();
return await pro.DownloadTvChannels();
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这不是从"顶部"异步运行的.由于无法async在Main方法上指定修饰符,如何在main异步中运行代码?
Ste*_*ary 354
正如您所发现的,在VS11中,编译器将禁止使用某种async Main方法.在VS2010中使用Async CTP允许(但从未推荐).
我最近有关于async/await和异步控制台程序的博客文章.以下是介绍帖子的一些背景信息:
如果"等待"看到等待未完成,那么它就是异步行为.它告诉等待在完成时运行方法的其余部分,然后从异步方法返回.当Await将方法的其余部分传递给等待时,Await 也将捕获当前上下文.
稍后,当等待完成时,它将执行异步方法的剩余部分(在捕获的上下文中).
这就是为什么这是Console程序中的一个问题async Main:
请记住,在我们的介绍文章中,异步方法将在完成之前返回其调用方.这在UI应用程序中完美运行(该方法只返回到UI事件循环)和ASP.NET应用程序(该方法返回线程但保持请求处于活动状态).它对Console程序来说效果不佳:主要返回操作系统 - 所以程序退出.
一种解决方案是提供您自己的上下文 - 控制台程序的"主循环",它是异步兼容的.
如果您有与异步CTP机器,你可以使用GeneralThreadAffineContext从我的文档\微软的Visual Studio异步CTP \样品(C#测试)单元测试\ AsyncTestUtilities.另外,您也可以使用AsyncContext从我Nito.AsyncEx NuGet包.
这是一个使用的例子AsyncContext; GeneralThreadAffineContext具有几乎相同的用法:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以阻止主控制台线程,直到您的异步工作完成:
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Run Code Online (Sandbox Code Playgroud)
注意使用GetAwaiter().GetResult(); 这可以避免在AggregateException使用Wait()或时发生的包装Result.
更新,2017-11-30:从Visual Studio 2017 Update 3(15.3)开始,该语言现在支持async Main- 只要它返回Task或Task<T>.所以你现在可以这样做:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Run Code Online (Sandbox Code Playgroud)
语义似乎与GetAwaiter().GetResult()阻塞主线程的样式相同.但是,C#7.1还没有语言规范,所以这只是一个假设.
Chr*_*ini 351
你可以用这个简单的结构解决这个问题:
class Program
{
static void Main(string[] args)
{
Task.Run(async () =>
{
// Do any async anything you need here without worry
}).GetAwaiter().GetResult();
}
}
Run Code Online (Sandbox Code Playgroud)
这将把你所做的一切都放在你想要它的ThreadPool上(所以你开始/等待的其他任务不会尝试重新加入他们不应该的线程),并等到关闭Console应用程序之前完成所有操作.不需要特殊循环或外部库.
编辑:将Andrew的解决方案纳入未捕获的异常.
Ste*_*ers 90
您可以通过执行以下操作而无需外部库来执行此操作:
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>
Task.WaitAll(getListTask); // block while the task completes
var list = getListTask.Result;
}
}
Run Code Online (Sandbox Code Playgroud)
Cor*_*son 74
我将添加一个重要的功能,所有其他答案都忽略了:取消.
TPL的一大特色是取消支持,控制台应用程序有一种内置取消方法(CTRL + C).将它们绑定在一起非常简单.这就是我构建所有异步控制台应用程序的方式:
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
static async Task MainAsync(string[] args, CancellationToken token)
{
...
}
Run Code Online (Sandbox Code Playgroud)
naw*_*fal 71
在C#7.1中,您将能够执行正确的异步Main.Main方法的适当签名已扩展为:
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
Run Code Online (Sandbox Code Playgroud)
例如,你可能会这样做:
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
Run Code Online (Sandbox Code Playgroud)
在编译时,异步入口点方法将转换为调用GetAwaitor().GetResult().
详细信息:https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main
编辑:
要启用C#7.1语言功能,您需要右键单击项目并单击"属性",然后转到"构建"选项卡.在那里,单击底部的高级按钮:
从语言版本下拉菜单中,选择"7.1"(或任何更高的值):
默认为"最新主要版本",它将评估(在撰写本文时)C#7.0,它不支持控制台应用程序中的异步主.
Joh*_*alk 19
还没有需要这么多,但是当我使用控制台应用程序进行快速测试并且需要异步时,我刚刚解决了这个问题:
class Program
{
static void Main(string[] args)
{
MainAsync(args).Wait();
}
static async Task MainAsync(string[] args)
{
// Code here
}
}
Run Code Online (Sandbox Code Playgroud)
M.H*_*san 19
C#7.1(使用vs 2017更新3)引入了async main
你可以写:
static async Task Main(string[] args)
{
await ...
}
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅C#7系列,第2部分:Async Main
更新:
您可能会收到编译错误:
程序不包含适用于入口点的静态"Main"方法
此错误是由于vs2017.3默认配置为c#7.0而不是c#7.1.
您应该明确修改项目的设置以设置c#7.1功能.
您可以通过两种方法设置c#7.1:
方法1:使用项目设置窗口:
方法2:手动修改.csproj的PropertyGroup
添加此属性:
<LangVersion>7.1</LangVersion>
Run Code Online (Sandbox Code Playgroud)
例:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)
Şaf*_*Gür 18
如果您使用C#7.1或更高版本,去与nawfal的回答,只是改变你的主要方法的返回类型Task或Task<int>.如果你不是:
async Task MainAsync 像约翰说的那样..GetAwaiter().GetResult()来捕获像do0g所说的底层异常.CTRL+C应立即终止该过程.(谢谢binki!)OperationCancelledException- 返回适当的错误代码.最终代码如下:
private static int Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = !cts.IsCancellationRequested;
cts.Cancel();
};
try
{
return MainAsync(args, cts.Token).GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
return 1223; // Cancelled.
}
}
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
// Your code...
return await Task.FromResult(0); // Success.
}
Run Code Online (Sandbox Code Playgroud)
要从Main异步调用任务,请使用
.NET 4.5的Task.Run()
.NET 4.0的Task.Factory.StartNew()(可能需要Microsoft.Bcl.Async库用于异步和等待关键字)
详细信息:http: //blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
最新版本的 C# - C# 7.1 允许创建异步控制台应用程序。要在项目中启用 C# 7.1,您必须将 VS 升级到至少 15.3,并将 C# 版本更改为C# 7.1或C# latest minor version。为此,请转到项目属性 -> 构建 -> 高级 -> 语言版本。
之后,以下代码将起作用:
internal class Program
{
public static async Task Main(string[] args)
{
(...)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
180853 次 |
| 最近记录: |