为什么任务甚至在等待中完成
Why Task finishes even in await
我在以下代码中遇到问题:
static void Main (string[] args)
{
Task newTask = Task.Factory.StartNew(MainTask);
newTask.ContinueWith ((Task someTask) =>
{
Console.WriteLine ("Main State=" + someTask.Status.ToString () + " IsFaulted=" + someTask.IsFaulted+" isComplete="+someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
Task someTask = Task.Factory.StartNew (() =>
{
Console.WriteLine ("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine ("SleepEnded!");
});
await someTask;
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
我只想从新开始的任务中获取异常 MainTask
。但是结果不是我想象的那样。
MainStarted!
Main State = RanToCompletion IsFaulted = False isComplete = True
SleepStarted!
SleepEnded!
Waiting Ended!!
如您所见,任务在 "Waiting Ended!!" 控制台日志之前完成。
我不知道为什么 MainTask
结束,即使 MainTask
里面有 await
命令?
我错过了什么吗?
Task.Factory.StartNew
does not understand async delegates 所以你需要在这种情况下使用 Task.Run
并且异常应该流过。
Task.Factory.StartNew(MainTask);
本质上等同于
Task.Factory.StartNew(() => MainTask);
它忽略了从 MainTask
返回的任务并且异常被吞没了。
查看此blog post了解更多详情。
尝试使用 Task.Run
,您会得到异常:
void Main(string[] args)
{
Task newTask = Task.Run(MainTask);
newTask.ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
Console.WriteLine("Waiting Ended!!");
throw new Exception("CustomException!");
Console.WriteLine("NeverReaches here!!");
}
我在这里修改了你的问题以捕获异常。
static void Main(string[] args)
{
DoFoo();
Console.ReadKey();
}
static async void DoFoo()
{
try
{
await Foo();
}
catch (Exception ex)
{
//This is where you can catch your exception
}
}
static async Task Foo()
{
await MainTask().ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
}, TaskContinuationOptions.NotOnFaulted);
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
throw new Exception("CustomException!");
Console.WriteLine("Waiting Ended!!");
}
您应该使用 TaskContinuationOptions.NotOnFaulted
,这意味着仅当父任务没有任何异常时,continue with 任务才会执行。
这里有很好的答案,但我想指出一个显而易见的问题 - Task.Factory.StartNew
完全是多余的、不必要的并且用错了。
如果你更换
Task newTask = Task.Factory.StartNew(MainTask);
和
Task newTask = MainTask();
您将获得您期望的行为,而不会浪费另一个线程池线程来启动 另一个 线程池线程。事实上,如果您想重写您的示例以使其更加地道,您可以使用如下内容:
static void Main (string[] args)
{
var task =
MainTask()
.ContinueWith(t => Console.WriteLine("Main State={0}", t.Status));
task.Wait();
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
await Task.Delay(1000);
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
此代码仅对延迟后的代码使用线程池线程,并在 task.Wait()
调用时重新抛出异常 - 当然,您可能想做其他事情。
附带说明一下,即使您不想显式等待任务完成,也不应使用 while (true) {}
来阻止应用程序终止 - 一个简单的 Console.ReadLine()
也可以正常工作,并且不会将您的 CPU 核心之一推至 100% 利用率 :)
我在以下代码中遇到问题:
static void Main (string[] args)
{
Task newTask = Task.Factory.StartNew(MainTask);
newTask.ContinueWith ((Task someTask) =>
{
Console.WriteLine ("Main State=" + someTask.Status.ToString () + " IsFaulted=" + someTask.IsFaulted+" isComplete="+someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
Task someTask = Task.Factory.StartNew (() =>
{
Console.WriteLine ("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine ("SleepEnded!");
});
await someTask;
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
我只想从新开始的任务中获取异常 MainTask
。但是结果不是我想象的那样。
MainStarted!
Main State = RanToCompletion IsFaulted = False isComplete = True
SleepStarted!
SleepEnded!
Waiting Ended!!
如您所见,任务在 "Waiting Ended!!" 控制台日志之前完成。
我不知道为什么 MainTask
结束,即使 MainTask
里面有 await
命令?
我错过了什么吗?
Task.Factory.StartNew
does not understand async delegates 所以你需要在这种情况下使用 Task.Run
并且异常应该流过。
Task.Factory.StartNew(MainTask);
本质上等同于
Task.Factory.StartNew(() => MainTask);
它忽略了从 MainTask
返回的任务并且异常被吞没了。
查看此blog post了解更多详情。
尝试使用 Task.Run
,您会得到异常:
void Main(string[] args)
{
Task newTask = Task.Run(MainTask);
newTask.ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
Console.WriteLine("Waiting Ended!!");
throw new Exception("CustomException!");
Console.WriteLine("NeverReaches here!!");
}
我在这里修改了你的问题以捕获异常。
static void Main(string[] args)
{
DoFoo();
Console.ReadKey();
}
static async void DoFoo()
{
try
{
await Foo();
}
catch (Exception ex)
{
//This is where you can catch your exception
}
}
static async Task Foo()
{
await MainTask().ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
}, TaskContinuationOptions.NotOnFaulted);
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
throw new Exception("CustomException!");
Console.WriteLine("Waiting Ended!!");
}
您应该使用 TaskContinuationOptions.NotOnFaulted
,这意味着仅当父任务没有任何异常时,continue with 任务才会执行。
这里有很好的答案,但我想指出一个显而易见的问题 - Task.Factory.StartNew
完全是多余的、不必要的并且用错了。
如果你更换
Task newTask = Task.Factory.StartNew(MainTask);
和
Task newTask = MainTask();
您将获得您期望的行为,而不会浪费另一个线程池线程来启动 另一个 线程池线程。事实上,如果您想重写您的示例以使其更加地道,您可以使用如下内容:
static void Main (string[] args)
{
var task =
MainTask()
.ContinueWith(t => Console.WriteLine("Main State={0}", t.Status));
task.Wait();
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
await Task.Delay(1000);
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
此代码仅对延迟后的代码使用线程池线程,并在 task.Wait()
调用时重新抛出异常 - 当然,您可能想做其他事情。
附带说明一下,即使您不想显式等待任务完成,也不应使用 while (true) {}
来阻止应用程序终止 - 一个简单的 Console.ReadLine()
也可以正常工作,并且不会将您的 CPU 核心之一推至 100% 利用率 :)