我正在尝试从Thread
到Task
进行代码替换。睡眠/延迟只表示长时间运行。
static void Main(string[] args)
{
ThreadDoWork();
TaskDoWork();
}
public static void ThreadDoWork()
{
using (var dispose = new ThreadDispose())
{
dispose.RunAsync();
}
}
public static async void TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
public class ThreadDispose : IDisposable
{
public void RunAsync ()
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(3000);
});
}
void IDisposable.Dispose()
{
File.AppendAllText("D:\\test.txt", "thread disposing");
}
}
public class TaskDispose : IDisposable
{
public async Task RunAsync()
{
await Task.Delay(3000);
}
void IDisposable.Dispose()
{
File.AppendAllText("D:\\test.txt", "task disposing");
}
}
test.txt
中3秒后的结果仅为
线程处理
我需要更改TaskDispose::Dispose
按顺序执行的更改ThreadDispose
答案 0 :(得分:22)
让我们隔离每段代码:
public static void ThreadDoWork()
{
using (var dispose = new ThreadDispose())
{
dispose.RunAsync();
}
}
public void RunAsync()
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(3000);
});
}
您在第一段代码中所做的是在线程池线程上进行队列工作。因为您在using
范围内运行此代码并且它在不同的线程上异步运行,所以它会立即处理 。这就是您在文本文件中看到dispose消息的原因。
public static async void TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
public class TaskDispose : IDisposable
{
public async Task RunAsync()
{
await Task.Delay(3000);
}
}
当你在方法中await
时,你实际说的是:"执行此代码。因为它本质上是异步的,所以我会将控制权返回给调用方法,一旦完成异步操作" ,请给我回电话。
您的代码会点击await
关键字并将控制权返回到您的Main
方法。在Main
内,您的异步方法是要执行的最后一段代码,因此完成了您的应用程序,并且没有机会让您的Dispose
方法执行。
如果您希望将其处置,则必须将返回类型从void
更改为Task
并明确Wait
:
public static async Task TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
现在:
static void Main(string[] args)
{
ThreadDoWork();
TaskDoWork().Wait();
}
旁注:
应遵循以下几条准则:
async void
与事件处理程序的兼容性很少,在该范围之外的场合很少会被使用。相反,请使用async Task
。
使用TAP(任务异步模式)执行异步操作的方法应以Async
后缀结束。 TaskDoWork
应为TaskDoWorkAsync
在Wait
上使用Task
会导致死锁。在这种特殊情况下,它并不是因为控制台应用程序没有SynchronizationContext
并使用线程池。推荐的方法是一直“异步”#34;并使用await
async-await tag wiki内有很棒的阅读材料,请务必查看。
答案 1 :(得分:-1)
这两个例子都有问题。 第一个,在线程的情况下,Dispose方法在线程结束之前调用。 在任务的情况下,任务完成后将调用Dispose方法。
但是文件只有线程大小写的文本,因为在调用RunAsync方法后它会被同步调用。并且任务案例不会写任何内容,因为应用程序在任务完成之前已经结束。
测试等待任务完成Thread.Sleep(5000),例如在Main方法结束时,任务应写入输出文件。