使用 Visual Studio 2015,针对 FW 4(在 FW 4 下测试不可观察的异常):
我期待这段代码:
static void Main(string[] args)
{
try
{
Task.Factory.StartNew(() => Console.WriteLine(1))
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => Console.WriteLine(2))
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => { throw new Exception("aaaa"); })
.ContinueWith(t => Console.WriteLine(3));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
GC.Collect();
GC.Collect();
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
向我展示例外情况。
我知道我可以通过T.Wait()或在最后一个任务中看到它t.Exception- 但为什么我在这里没有看到异常?
我知道异常处理机制在 4.5 中发生了变化,为了获得旧的机制,我应该添加:
<ThrowUnobservedTaskExceptions enabled="true"/>
Run Code Online (Sandbox Code Playgroud)
我做了什么:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)
但结果仍然是: …
我遇到了以下使用 ContinueWith() 等待结果的代码。
public async Task<User> GetUser()
{
return await _serviceRepo.GetUserAsync()
.ContinueWith(task =>
{
return task.Result;
});
}
Run Code Online (Sandbox Code Playgroud)
是否ContinueWith()阻塞调用线程直到任务从GetUserAsync()调用返回?
由于 位于task.Result已安排的 ContinueWith() 内,在等待前件时task是否有任何内容被阻止?
我在其他几个地方看到过这种类型的代码,这被认为是异步/等待模式的最佳实践吗?我希望GetUserAsync()调用返回结果而不是使用 aContinueWith()来等待它。
我正在测试 C# async/await 的异步性,遇到了一个惊喜,即 ContinueWith 的后续代码不等待前一个任务完成:
public async Task<int> SampleAsyncMethodAsync(int number,string id)
{
Console.WriteLine($"Started work for {id}.{number}");
ConcurrentBag<int> abc = new ConcurrentBag<int>();
await Task.Run(() => { for (int count = 0; count < 30; count++) { Console.WriteLine($"[{id}] Run: {number}"); abc.Add(count); } });
Console.WriteLine($"Completed work for {id}.{number}");
return abc.Sum();
}
Run Code Online (Sandbox Code Playgroud)
这是使用以下测试方法执行的:
[Test]
public void TestAsyncWaitForPreviousTask()
{
for (int count = 0; count < 3; count++)
{
int scopeCount = count;
var c = SampleAsyncMethodAsync(0, scopeCount.ToString())
.ContinueWith((prevTask) =>
{
return SampleAsyncMethodAsync(1, scopeCount.ToString()); …Run Code Online (Sandbox Code Playgroud) 我已经读过这个问题,但就我而言,它更简单,因为我不必使用Result属性。所以我想知道我是否可以采用比斯蒂芬·克利里的答案提供的更简单的方法。
假设我有这个简单的界面。
internal interface IBinaryDataReadable
{
Task Load(AsyncDataReader reader);
}
Run Code Online (Sandbox Code Playgroud)
该接口提供了异步加载对象的方法。它不返回任何内容,因为加载结果是对象本身。
(该接口是内部的,因此显式实现以避免暴露实现。)
这是我加载二进制数据的方法。
data = new BinaryData();
await ((IBinaryDataReadable)data).Load(reader);
Run Code Online (Sandbox Code Playgroud)
我想让它更加流畅和详细,所以我编写了这个扩展方法
internal static Task<TData> Load<TData>(this TData data, AsyncDataReader reader)
where TData : IBinaryDataReadable
=> data.Load(reader).ContinueWith(t => data, TaskContinuationOptions.ExecuteSynchronously);
Run Code Online (Sandbox Code Playgroud)
现在加载就变成这样了。
data = await new BinaryData().Load(reader);
Run Code Online (Sandbox Code Playgroud)
使用此方法有什么我应该担心的吗?例如异常处理等?
我有以下代码在.NET Standard 2.0上运行:
public static Task<JobResult> TryRunAsync(this IJob job,
CancellationToken cancellationToken = default(CancellationToken))
{
return job.RunAsync(cancellationToken)
.ContinueWith(t => {
if (t.IsFaulted)
return JobResult.FromException(t.Exception.InnerException);
if (t.IsCanceled)
return JobResult.Cancelled;
return t.Result;
});
}
Run Code Online (Sandbox Code Playgroud)
我们注意到它没有按预期运行.我们认为当你等待对TryRun的调用时,它总是会调用可以处理异常/取消并返回作业结果的延续.我们希望减少创建的异步状态机的数量......然而,事实并非如此,它只会爆炸.这是一个较小的示例(创建一个新的.net核心2.0控制台应用程序并粘贴以下内容:
using System;
using System.Threading.Tasks;
namespace ConsoleApp4
{
public class Program
{
public static async Task Main()
{
// works
await DoStuff();
Console.ReadKey();
// blows up
await TryRun();
Console.ReadKey();
}
public static Task DoStuff()
{
return Method()
.ContinueWith(t => Throws())
.ContinueWith(t => {
if (t.IsFaulted)
Console.WriteLine("Faulted");
else …Run Code Online (Sandbox Code Playgroud) 我试图从异步方法执行两个不同的任务,但我的第二个任务应该从第一个任务开始.我试过使用ContinueWith但没有成功.这是我的示例代码:
class Program
{
static List<string> GlobalList1 = null;
static List<string> GlobalList2 = null;
static void Main(string[] args)
{
Task firstTask = new Task(DoFirstThing);
firstTask.Start();
firstTask.Wait();
Task secondTask = firstTask.ContinueWith(o => DoSecondThing(), TaskContinuationOptions.ExecuteSynchronously);
secondTask.Wait();
Console.ReadKey();
}
public async static void DoFirstThing()
{
Console.WriteLine("Doing first...");
Task t = new Task(FirstThing);
t.Start();
await t;
}
public async static void DoSecondThing()
{
Console.WriteLine("Doing second...");
Task t = new Task(SecondThing);
t.Start();
await t;
}
private async static void FirstThing()
{
Console.WriteLine("In First..");
Task t …Run Code Online (Sandbox Code Playgroud)