您同时有多个登录不是将其放在单独线程中的理由。
对我理解 async-await 有很大帮助的一件事是 this interview with Eric Lippert。在中间的某处搜索异步等待。
他将 async-await 与必须做几份早餐的厨师进行比较。厨师打开水壶煮茶。他没有等到水沸腾了。相反,他环顾四周,看看是否可以做其他事情:他可以将面包放入烤面包机,或者从第二份早餐开始。
请注意,厨师必须等待的唯一时刻是另一个进程(例如水壶或面包烤面包机)正在做某事时:如果厨师空闲等待或不等待,则 if 不会加速该过程。
您会在计算机中看到类似的情况:您会发现 async await 仅在涉及另一个自治进程时。就像当你想将数据写入磁盘,或者从数据库管理系统查询数据,或者从互联网上读取信息时:你的进程不能做任何事情来加速这个进程,而另一个进程正在做它的事情,你的进程可以做其他事情,比如听新的操作员输入。
如果厨师还要做一些繁重的加工,比如切西红柿,他会忙着处理热吐司。在这种情况下,最好聘请第二位厨师来切西红柿。水开后烤面包,厨师要等第二位厨师切完后才能继续做早餐。
您的问题是一样的:您要求操作员或进程登录。您可以做其他事情,而不是无所事事地等待登录完成,例如开始下一次登录,当该登录等待完成时,您可以开始第三次登录:全部由同一个线程完成。
只有当你必须做一些冗长的繁重处理,而不是无所事事地等待时,让一个单独的线程来做这些繁重的计算可能是有用的。只有这样做,才能让您的来电者保持响应。如果在你忙着切西红柿的时候打电话的人都没有做任何有用的事情,那就不要为此雇一个额外的厨师,因为这会让你闲着,结果就是吃完早餐需要更长的时间。
顺便说一句:每个 Async 方法都返回 Task<TResult> 而不是 TResult 和 Task 而不是 void。此规则只有一个例外:事件处理程序返回async void,没有人可以等待事件处理程序完成。
所以你的 api 有一个 LoginAsync,你想创建一个函数来使用这个 Login。也许您还有其他一些登录名,并且您想全部调用它们,而无需等待(好吧,如果没有人完成登录,您将无事可做)
- 异步任务 LoginAsync() // = 来自您的 API 的登录
Login 方法,让我们把它做成一个同步和异步版本,这样你就会明白为什么将登录操作与登录处理分开是明智的:
void Login()
{
LoginResult loginResult = api.Login();
this.ProcessLoginResult(loginResult);
}
async Task LoginAsync()
{
LoginResult loginResult = await api.Login();
this.ProcessLoginResult(loginResult);
// as this is not a lengthy process, there is no async method
}
您在谈论多个登录,因此假设您有一个启动多个登录的过程。显然你的登录方法不需要通知他们的调用者登录结果,你只需要知道它们是否都完成了:
async Task PerformMultipleLoginsAsync()
{
// start Login 1, do not await yet
Task taskLogin1 = this.LoginAsync();
// because you did not await, you are free to do something else
// while LoginAsync is awaiting
this.DoSomething();
// start a second Login. The first might be finished, but you don't care about
// that right now
Task taskLogin2 = this.LoginAsync();
this.DoSomethingElse();
// now you need the 1st login to finish
await taskLogin1;
// or if you need both logins to be finished
await Task.WhenAll(new Task[] {taskLogin1, taskLogin2});
// of if you need that at least one login is finished:
await Task.WhenAny(new Task[] {taskLogin1, taskLogin2});
}
如果您登录多个进程并希望在任何进程完成后立即执行某项操作,那么等待任何登录会很好:
HashSet<Task<LoginResult>> loginTasks = new HashSet(this.StartManyLogins());
while (loginTasks.Any())
{
Task<LoginResult> finishedTask = await Tasks.WhenAny(loginTasks);
LoginResult loginResult = finishedTask.Result;
this.ProcessLoginResult(loginResult);
loginTasks.Remove(finishedTask);
}