我试图在已经存在的非常大的同步代码库中使用async/await。在这个代码库中有一些全局状态,如果kludgy在同步上下文中工作正常,但它在async/await的异步上下文中不起作用。使用异步/等待,什么时候连续发生?
所以,我的两个选择似乎是两种因素走出全球范围内其woould是一个非常大和非常耗时的任务,或者做一些巧妙的搭配延续时运行。
为了更好地理解异步/等待和延续,我做了一个测试程序,如下图所示。显示在这里。
// A method to simulate an Async read of the database.
private static Task ReadAsync()
{
return Task.Factory.StartNew(() =>
{
int max = int.MaxValue/2;
for (int i = 0; i < max; ++i)
{
}
});
}
// An async method that creates several continuations.
private static async Task ProcessMany(int i)
{
Console.WriteLine(string.Format("{0} {1}", i.ToString(), 0));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1}", i.ToString(), 1));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1}", i.ToString(), 2));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1}", i.ToString(), 3));
}
public static void Main(string[] args)
{
Queue<Task> queue = new Queue<Task>();
for (int i = 0; i < 10; ++i)
{
queue.Enqueue(ProcessMany(i));
}
// Do some synchonous processing...
Console.WriteLine("Processing... ");
for (int i = 0; i < int.MaxValue; ++i)
{
}
Console.WriteLine("Done processing... ");
queue.Dequeue().Wait();
}
阅读所有关于异步后/ AWAIT,我的理解是,没有一个延续的会之间发生“处理..”和“处理完毕后......” WriteLines。
以下是一些示例输出。
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
Processing...
3 1
2 1
7 1
6 1
0 1
4 1
5 1
1 1
6 2
3 2
Done processing...
7 2
2 2
0 2
4 2
5 2
1 2
6 3
3 3
7 3
2 3
0 3
我希望单等待()在程序结束时,而第一个完成可能产生多个延续,但我不知道如何延续的任何可能“处理之间运行.. 。“和”完成处理...“。我认为在Console.WriteLine方法中可能存在yield或者某种东西,所以我完全替换了它,但是这并没有改变输出。
很明显我在异步的理解差距/等待。当我们只是递增一个变量时,怎么会发生延续?编译器还是CLR在这里注入某种魔力?
预先感谢您的任何帮助更好地理解异步/等待和延续。
编辑:
如果这样按照斯蒂芬注释编辑示例代码,这是怎么回事更加明显。
// An async method that creates several continuations.
private static async Task ProcessMany(int i)
{
Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 0, Thread.CurrentThread.ManagedThreadId));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 1, Thread.CurrentThread.ManagedThreadId));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 2, Thread.CurrentThread.ManagedThreadId));
await ReadAsync();
Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 3, Thread.CurrentThread.ManagedThreadId));
}
public static void Main(string[] args)
{
Queue<Task> queue = new Queue<Task>();
for (int i = 0; i < 10; ++i)
{
queue.Enqueue(ProcessMany(i));
}
// Do some synchonous processing...
Console.WriteLine("Processing... {0}", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < int.MaxValue; ++i)
{
}
Console.WriteLine("Done processing... {0}", Thread.CurrentThread.ManagedThreadId);
queue.Dequeue().Wait();
}
输出:
0 0 9
1 0 9
2 0 9
3 0 9
4 0 9
5 0 9
6 0 9
7 0 9
8 0 9
9 0 9
Processing... 9
4 1 14
3 1 13
2 1 12
5 1 15
0 1 10
6 1 16
1 1 11
7 1 17
4 2 14
3 2 13
0 2 10
6 2 16
2 2 12
5 2 15
Done processing... 9
1 2 11
7 2 17
0 3 10
4 3 14
谢谢,我几乎在你发布的同一时间就意识到了这一点。我编辑了示例代码,现在它变得更有意义。 – Ashley
所以,这意味着在非UI上下文中,继续必须是线程安全的?我认为异步/等待的巨大好处意味着您不必担心线程安全性,因为它将全部在主线程上运行。 :\ – Ashley
我的全局状态与数据库连接和数据库事务有关,它们以非常复杂的方式编入代码库,然后解开它将会非常困难。这是一个30岁的代码库,已经通过多个端口转向新语言。 :) – Ashley