我的任务是容器化遗留控制台工作应用程序,我在各处使用 async\await 重写了该应用程序。我的上级质疑我的选择,因为没有理由将其引入到独立的单线程应用程序中,因为线程池不太可能耗尽。我没有答案来证明使用它的合理性,除了它是相当长一段时间以来编写代码的标准方法之外。它有什么实质性的好处吗?
我下面的演练如何使用的EntityFramework WPF结合.我决定玩async/await,因为我之前从未真正有机会使用它(我们刚从VS2010/.NET 4.0转移到VS2013/.NET 4.5).让保存按钮处理程序变为异步是轻而易举的,并且在等待SaveChangesAsync()时,UI仍然保持响应(我可以拖动窗口).然而,在窗口加载处理程序中,我遇到了一个小问题.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
EnterBusyState();
var categoryViewSource = (CollectionViewSource)FindResource("categoryViewSource");
_context = await Task.Run(() => new Context());
await Task.Run(() => _context.Categories.Load());
//await _context.Categories.LoadAsync();
categoryViewSource.Source = _context.Categories.Local;
LeaveBusyState();
}
Run Code Online (Sandbox Code Playgroud)
当我使用第一种加载_context.Categories的方式时,UI仍然保持响应,但是当我用下面的注释掉的行代替时,UI会在实体加载时冻结一小段时间.有没有人解释为什么前者有效而后者无效呢?这不是什么大不了的事情,只是在第二行无法工作的时候,至少根据我迄今为止研究过的async/await,它应该是不行的.
我最近阅读了 Stephen Cleary 的文章,内容涉及当我们在同步方法中调用异步代码时可能发生的死锁:https: //blog.stephencleary.com/2012/07/dont-block-on-async-code.html
关于这里稍微修改的示例(我添加的只是一个 writeline 代码):
// My "library" method.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
Console.WriteLine("Before await");
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(true);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public void Button1_Click(...)
{
var jsonTask = GetJsonAsync(...);
textBox1.Text = jsonTask.Result;
}
Run Code Online (Sandbox Code Playgroud)
他的解释是,顶级方法正在阻塞等待GetJsonAsync完成的 UI 线程,同时GetJsonAsync正在等待 UI 线程被释放,以便它可以完成执行。
我的问题是,不是GetJsonAsync已经在 UI 线程上了吗?为什么需要等待它被释放?根据这篇文章,调用异步函数不一定会创建另一个线程来执行该方法。GetJsonAsync那么,如果一直在 UI 线程上执行,会如何导致 UI 线程出现问题呢?就像什么时候Console.WriteLine()执行,如果不在 UI 线程上,那么在哪里完成?我觉得我在这里错过了一些东西,但不知道是什么。
澄清:执行在什么时候离开 …
还有一个关于线程安全和 async/await 的问题。我不明白为什么我的第二个增量不是线程安全的。
class Program
{
static int totalCountB = 0;
static int totalCountA = 0;
static async Task AnotherTask()
{
totalCountA++; // Thread safe
await Task.Delay(1);
totalCountB++; // not thread safe
}
static async Task SpawnManyTasks(int taskCount)
{
await Task.WhenAll(Enumerable.Range(0, taskCount)
.Select(_ => AnotherTask()));
}
static async Task Main()
{
await SpawnManyTasks(10_000);
Console.WriteLine($"{nameof(totalCountA)} : " + totalCountA); // Output 10000
Console.WriteLine($"{nameof(totalCountB)} : " + totalCountB); // Output 9856
}
}
Run Code Online (Sandbox Code Playgroud)
我的理解是:
totalCountA++是线程安全的,因为在那之前,代码是完全同步的。await可能会在线程池上运行,但我没想到恢复的代码await将完全是多线程的。根据一些答案/博客,async/await …
I read the Microsoft document about async and await. It says:
The async and await keywords don't cause additional threads to be created.
But I run the below code
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Task task = Test();
task.Wait();
}
public async static Task Test()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
}
}
Run Code Online (Sandbox Code Playgroud)
The result is
1
1
4
It is obvious that the
await …Run Code Online (Sandbox Code Playgroud) 这是AsyncMethods类看起来像:
public class AsyncMethods
{
public static async Task<double> GetdoubleAsync()
{
Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
return 80d;
}
public static async Task<string> GetStringAsync()
{
Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
return "async";
}
public static async Task<DateTime> GetDateTimeAsync()
{
Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
return DateTime.Now;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的主要方法:
static void Main(string[] args)
{
while (Console.ReadLine() != "exit")
{
Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
DateTime dt = DateTime.Now;
var res = GetStuffAsync().Result;
var ts = DateTime.Now …Run Code Online (Sandbox Code Playgroud)