异步代码在 aspnet 标识中具有误导性
Async code misleading in aspnet identity
我需要为 aspnetidentity 实现自定义存储提供程序。
我环顾四周,发现相当多 few.However 它们对我来说似乎都是错误的。
我的理解是,如果你有一个以 "async" 结尾的方法,那么它应该是异步的。
查看从某人的代码中获取的示例,它散布在各处。
我发现下面的内容非常具有误导性,因为从我所看到的来看它根本不是异步的:
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser; //this is not async
if (result != null)
{
return Task.FromResult<TUser>(result);
}
return Task.FromResult<TUser>(null);
}
应该这样编码吗?:
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return await Task.FromResult<TUser>(result);
}
return await Task.FromResult<TUser>(null);
}
Questions?
这样做"Task.FromResult"是否正确?我的意思是“Task.FromResult 实际上变成了同步?它应该是什么?
编写上述代码的正确方法是什么? configureAwait(false) 怎么样
异步应该是 "All the way down including datalayer to avoid deadlocking"
任何示例代码/片段将不胜感激
非常感谢任何反馈
初始代码绝对不是异步的。它看起来像是为了应对 API 设计。
然而,提议的更改对我来说也不是异步的。 Task.FromResult
只是创建一个已完成的任务并给出结果,不会使任何异步操作或执行任何类型的可等待代码,因此您不应该等待它。
在您的情况下,假设 GetUserByIdAsync
return 是 Task<TUser>
,并假设此代码的全部目的(看起来)总是 return 完成任务(从未出错或取消),这可以重写为:
public async Task<TUser> FindByIdAsync(int userId)
{
var tResult = userTable.GetUserByIdAsync(userId);
TUser result = null;
try
{
result = await tResult;
}
except
{
// Bad idea, but here goes to your first snippet
}
return Task.FromResult<TUser>(result);
}
注意:正如@PanagiotisKanavos 评论的那样,这是个坏主意,它隐藏了一个可能的错误状态,你永远不会知道你的 null
结果是否出现未找到用户,或者出现错误情况:我会避免它。
如果 faulted/cancelled 状态有效,这可能只是:
public Task<TUser> FindByIdAsync(int userId)
{
return userTable.GetUserByIdAsync(userId);
}
async
方法是编译器构建某些东西的一种方式,return 承诺 我们的 未来.对于 .NET Framework 和 C#,这是 Task
.
await
指令接受任何 awaitable 而 Task
恰好是一个。它不知道也不关心被调用的 method/operations 是否真的是异步的。
Task.FromResult<T>
returns 一个已完成的任务,如果您在 async
方法内的 await
指令中使用它,它将被认为已同步完成并执行会继续。
因此,仅调用 Task.FromResult<T>
使用 async
和 await
最终只会浪费 CPU 编译器生成的代码的周期和内存在 运行 时间浪费了更多 CPU 周期和内存。
因为 async
方法总是 return 是 Task
一个决定让它隐含以提高可读性并给它某种 sync感觉。编译会将 return 值包装在 Task
中。这就是为什么您不能直接 return Task.FromResult<TUser>(result)
或 Task.FromResult<TUser>(null)
并等待它获取值的原因。
因此,async
等同于您的同步代码将是:
public async Task<TUser> FindByIdAsync(int userId)
{
var result = await userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return result;
}
return null;
}
或:
public async Task<TUser> FindByIdAsync(int userId)
{
return await userTable.GetUserByIdAsync(userId) as TUser;
}
代码没有误导性。 ASP.NET 身份框架旨在通过 returning Task
并通过向方法名称添加 Async
后缀来指示这一点来提供异步接口:
Task<TUser> FindByIdAsync(int userId)
但是,底层提供程序可能没有异步方法。在那种情况下,您无法创建异步实现,但您仍然必须实现接口,并且要做到这一点,将使用 Task.FromResult
与您在第一个代码片段中所做的完全相同。
使用同步代码实现异步方法
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser;
return Task.FromResult<TUser>(result);
}
如果您的底层提供程序支持异步方法,您应该使用 async 和 await。
使用异步代码实现异步方法
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = (await userTable.GetUserByIdAsync(userId)) as TUser;
return result;
}
请注意,Task.FromResult
未被使用。 Task.FromResult
仅当您有一个由同步代码创建的 TResult
并且必须将其转换为异步代码所需的 Task<TResult>
时才需要。
有时,您的底层提供者可以 return 所需的 Task<TUser>
而无需任何进一步的工作。在这种情况下,您可以删除 async 和 await 并仍然提供异步实现。这可能会导致代码效率稍高:
public Task<TUser> FindByIdAsync(int userId)
{
Task<TUser> result = userTable.GetUserByIdAsync(userId);
return result;
}
我需要为 aspnetidentity 实现自定义存储提供程序。 我环顾四周,发现相当多 few.However 它们对我来说似乎都是错误的。
我的理解是,如果你有一个以 "async" 结尾的方法,那么它应该是异步的。
查看从某人的代码中获取的示例,它散布在各处。
我发现下面的内容非常具有误导性,因为从我所看到的来看它根本不是异步的:
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser; //this is not async
if (result != null)
{
return Task.FromResult<TUser>(result);
}
return Task.FromResult<TUser>(null);
}
应该这样编码吗?:
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return await Task.FromResult<TUser>(result);
}
return await Task.FromResult<TUser>(null);
}
Questions?
这样做"Task.FromResult"是否正确?我的意思是“Task.FromResult 实际上变成了同步?它应该是什么?
编写上述代码的正确方法是什么? configureAwait(false) 怎么样 异步应该是 "All the way down including datalayer to avoid deadlocking"
任何示例代码/片段将不胜感激
非常感谢任何反馈
初始代码绝对不是异步的。它看起来像是为了应对 API 设计。
然而,提议的更改对我来说也不是异步的。 Task.FromResult
只是创建一个已完成的任务并给出结果,不会使任何异步操作或执行任何类型的可等待代码,因此您不应该等待它。
在您的情况下,假设 GetUserByIdAsync
return 是 Task<TUser>
,并假设此代码的全部目的(看起来)总是 return 完成任务(从未出错或取消),这可以重写为:
public async Task<TUser> FindByIdAsync(int userId)
{
var tResult = userTable.GetUserByIdAsync(userId);
TUser result = null;
try
{
result = await tResult;
}
except
{
// Bad idea, but here goes to your first snippet
}
return Task.FromResult<TUser>(result);
}
注意:正如@PanagiotisKanavos 评论的那样,这是个坏主意,它隐藏了一个可能的错误状态,你永远不会知道你的 null
结果是否出现未找到用户,或者出现错误情况:我会避免它。
如果 faulted/cancelled 状态有效,这可能只是:
public Task<TUser> FindByIdAsync(int userId)
{
return userTable.GetUserByIdAsync(userId);
}
async
方法是编译器构建某些东西的一种方式,return 承诺 我们的 未来.对于 .NET Framework 和 C#,这是 Task
.
await
指令接受任何 awaitable 而 Task
恰好是一个。它不知道也不关心被调用的 method/operations 是否真的是异步的。
Task.FromResult<T>
returns 一个已完成的任务,如果您在 async
方法内的 await
指令中使用它,它将被认为已同步完成并执行会继续。
因此,仅调用 Task.FromResult<T>
使用 async
和 await
最终只会浪费 CPU 编译器生成的代码的周期和内存在 运行 时间浪费了更多 CPU 周期和内存。
因为 async
方法总是 return 是 Task
一个决定让它隐含以提高可读性并给它某种 sync感觉。编译会将 return 值包装在 Task
中。这就是为什么您不能直接 return Task.FromResult<TUser>(result)
或 Task.FromResult<TUser>(null)
并等待它获取值的原因。
因此,async
等同于您的同步代码将是:
public async Task<TUser> FindByIdAsync(int userId)
{
var result = await userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return result;
}
return null;
}
或:
public async Task<TUser> FindByIdAsync(int userId)
{
return await userTable.GetUserByIdAsync(userId) as TUser;
}
代码没有误导性。 ASP.NET 身份框架旨在通过 returning Task
并通过向方法名称添加 Async
后缀来指示这一点来提供异步接口:
Task<TUser> FindByIdAsync(int userId)
但是,底层提供程序可能没有异步方法。在那种情况下,您无法创建异步实现,但您仍然必须实现接口,并且要做到这一点,将使用 Task.FromResult
与您在第一个代码片段中所做的完全相同。
使用同步代码实现异步方法
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser;
return Task.FromResult<TUser>(result);
}
如果您的底层提供程序支持异步方法,您应该使用 async 和 await。
使用异步代码实现异步方法
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = (await userTable.GetUserByIdAsync(userId)) as TUser;
return result;
}
请注意,Task.FromResult
未被使用。 Task.FromResult
仅当您有一个由同步代码创建的 TResult
并且必须将其转换为异步代码所需的 Task<TResult>
时才需要。
有时,您的底层提供者可以 return 所需的 Task<TUser>
而无需任何进一步的工作。在这种情况下,您可以删除 async 和 await 并仍然提供异步实现。这可能会导致代码效率稍高:
public Task<TUser> FindByIdAsync(int userId)
{
Task<TUser> result = userTable.GetUserByIdAsync(userId);
return result;
}