英文:
await task completion in a thread ends (breaks) this thread in C# .net6
问题
在线程函数中使用await
时遇到问题。似乎await
会中断线程。以下是一个演示这一点的测试类。
public class Question {
public static async Task<double> testTask() {
// [2]
await Task.Run(() => {
Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 100; i++) {
Task.Delay(10).Wait();
}
Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});
return 42.00;
}
static async Task ThreadFunction() {
Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
// [1]
//double x = await test.testTask().ConfigureAwait(true);
double x = await test.testTask();
int inserted = 0;
for (long i = 0; i < 100; i++)
System.Threading.Thread.Sleep(100);
// [3]
Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
public static void startTestThread() {
Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Thread TestThread = new Thread(() => ThreadFunction());
TestThread.Start();
TestThread.Join();
// [4]
Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
startTestThread() 在外部调用,作为一个控制台应用程序,没有主函数。
当程序执行到 double x = await test.testTask(); 时,线程"ThreadFunction"返回。这是我不理解的地方。线程应该等待函数testTask()完成。虽然函数被调用并且任务已经开始,但线程却被中断了。所以程序执行顺序不是:1 2 [3] [4],而是:1 2 [4],所以[3] 处的代码没有执行。为什么会这样?非常感谢社区的帮助。
英文:
have a problem when using await in a thread function.
It seems that await breaks the thread. Below the test class to demonstrate this.
public class Question {
public static async Task<double> testTask() {
// [2]
await Task.Run(() => {
Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 100; i++) {
Task.Delay(10).Wait();
}
Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});
return 42.00;
}
static async Task ThreadFunction() {
Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
// [1]
//double x = await test.testTask().ConfigureAwait(true);
double x = await test.testTask();
int inserted = 0;
for (long i = 0; i < 100; i++)
System.Threading.Thread.Sleep(100);
// [3]
Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
public static void startTestThread() {
Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Thread TestThread = new Thread(() => ThreadFunction());
TestThread.Start();
TestThread.Join();
// [4]
Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
startTestThread() is called from outside, a console application
in the new manner without a main function.
When program reaches
double x = await test.testTask();
Thread "ThreadFunction" returns.
Rhis is what i do not understand.
The thread should wait for function
testTask()
to get completed. The function is called and Task started
but the thread gets interrupted.
So the program execution sequence is not:
1 2 [3] [4]
instead it is:
1 2 [4]
, so code at [3] not executed. Why is this so? Many thanks to the community
答案1
得分: 3
你在许多地方都缺少了 async
和 await
。
此外,使用 Thread.Start
来运行一个 Task
是完全错误的,因为线程会在第一个 await
处结束。如果你想同步运行它,应该使用 Task.Run
和 Wait
,但请注意,如果设置了 SynchronizationContext
(在控制台应用程序中通常不会这样),可能会导致死锁。
理想情况下,你不应该在异步代码中执行同步操作。阅读一下这篇和这篇文章,了解为什么这是一个不好的做法。
public class Question
{
public static async Task<double> testTask()
{
// [2]
await Task.Run(async () => { // async HERE!!
Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 100; i++) {
await Task.Delay(10); // await HERE!!
}
Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});
return 42.00;
}
static async Task ThreadFunction()
{
Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
// [1]
//double x = await test.testTask().ConfigureAwait(true);
double x = await test.testTask();
int inserted = 0;
for (long i = 0; i < 100; i++)
await Task.Delay(100); // await HERE!!
// [3]
Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
public static void startTestThread() {
Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Task.Run(ThreadFunction).Wait();
// [4]
Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
我不清楚你尝试使用 ManagedThreadId
测试什么,但这很可能没有用。如果在使用带有 await
的任务时,你不应该关心自己在哪个线程上,同步上下文会处理这个问题。如果你正在使用线程,那么当然会保持在同一个线程上,因为你仍然在同一个函数调用中。
英文:
You are missing async
and await
in various places.
Furthermore, using Thread.Start
to run a Task
is wrong on so many levels: the thread will finish as soon as you hit the first await
. Instead, if you want to run it synchronously, use Task.Run
and Wait
, but note that you may get a deadlock if you have a SynchronizationContext
set up (not usually the case in a console app).
Ideally you shouldn't do sync-over-async ever. Take a read of this and this article for may reasons why this is a bad idea.
public class Question
{
public static async Task<double> testTask()
{
// [2]
await Task.Run(async () => { // async HERE!!
Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 100; i++) {
await Task.Delay(10); // await HERE!!
}
Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});
return 42.00;
}
static async Task ThreadFunction()
{
Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
// [1]
//double x = await test.testTask().ConfigureAwait(true);
double x = await test.testTask();
int inserted = 0;
for (long i = 0; i < 100; i++)
await Task.Delay(100); // await HERE!!
// [3]
Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
public static void startTestThread() {
Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
Task.Run(ThreadFunction).Wait();
// [4]
Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
I have no idea what you are trying to test with ManagedThreadId
but it's unlikely to be useful. If using tasks with await
then you shouldn't care which thread you are on, the synchronization context will sort that out. And if you were using threads then of course you remain on the same thread, you are still in the same function call.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论