c# 将通用 windows 应用程序转换为异步
c# converting universal windows app to async
我是 windows 的新手,我正在使用通用应用程序制作一个业余爱好项目。几天后,我发现连接串行端口的唯一方法是使用来自 SerialDevice class.
并与之相关的异步方法
我喜欢关于该主题的一般性建议:一旦你开始使用一个序列号 api,那么从 'Main' 开始将整个应用程序转换为异步会容易得多(http://blog.stephencleary.com/2012/02/async-and-await.html ) 而不是处理与异步方法的同步调用相关的问题。
然而,由 VS2015 创建的通用应用程序包含大量生成的非异步代码,这些代码并不旨在被理解。我想在某个地方有一个通用模式可以处理这个问题,但我找不到它的任何踪迹。那我该怎么办呢?
通用应用程序未被“此应用程序是异步的”和“此应用程序不是异步的”分隔,创建async
方法 而不是 意味着您必须绝对更改所有内容才能使用它们。
async
和 await
的好处之一是允许您在不冻结 UI.
的情况下执行长 运行 操作
Stephen Cleary 的“异步所有事物”模式完全没有必要,它滥用了异步方法的目的。
大多数代码不需要用异步方法包装,同步方法几乎可以处理所有事情。然而,对于 long-运行 进程,例如从 Web 服务请求数据,最适合异步方法,因为它需要很长时间。
重要的是您不要沉浸在创建数百万个 async
方法的异常模式中,找出 需要 什么是异步的并实现此功能因此。
之所以有些UWP API是async
是因为有些进程不是瞬时的,调用async
API方法时要记住,您要求 操作系统 代表您执行操作。事实上,操作系统可能 就绪 ,或者可能超载,可能无法立即满足您的请求,因此这些方法是异步的,这确保您的应用程序不会等待一个请求。
我建议您阅读此 here。
I suppose there is a general pattern somewhere do deal with this issue but I could not find any trace of it. So what should I do?
我的建议总是这样:
- 从 "leaves" 开始并识别自然异步操作。对于您的情况,这很容易,因为在 Windows 通用平台中,自然异步操作 只有 具有异步 API。
- 使用
await
调用异步 API。
await
的存在将要求调用方法为 async
(您应该将其 return 类型从 void
更改为 Task
或从 T
到 Task<T>
).
- 此转换使调用方法异步,因此返回步骤 (2) 它是 个调用方。
- 重复直到找到 "root" 方法 - 在 Windows 通用应用程序中,这通常是一个事件处理程序,必须是
async void
(它们不允许是async Task
).
您可能 运行 通过您的代码库遇到 async
"grows" 等各种问题 - 例如,您不能在 属性 中使用 await
吸气剂或构造函数。我有一个 series of posts on my blog describing techniques to work around these problems.
这是新手混淆的结果。
一个。术语 'async function' 具有三个含义:
A.1。签名中有 'async' 项的函数。该术语的唯一意义是编译器不会将函数体中的 'await' 视为变量,而是将其视为 await 语句。它不会以任何其他方式更改签名,它严格用于向后兼容。
A.2。可以等待的任务类型的函数。
A.3。主体中也有 await 语句的 Task 类型的函数。
乙。 UI 处理未被 await 语句阻塞:如果来自 UI 基础设施的一个回调正在等待 await 语句,UI 消息处理仍在执行。
因此,为了从 UI 方法调用异步函数 (A.2):
(a) 将 'async' 项添加到 UI 函数签名 (A.1)。
(b) 在函数内部使用await语句调用异步库函数(A.2)
(c) 以一种或另一种方式处理异步执行的结果。
async-await 模式引起的最大困惑是该模式只不过是将一个函数包装在任务中,运行 它和 return 运行ning Task(理解这一点非常重要,因为您并不总是希望您的 Task 自动启动...)。
一旦您意识到这一点,就应该更容易理解任何异步调用都可以很容易地被这样的任务包装。
public void PersistChanges()
{
var saveTask = new Task(() => PersistChangesAsync());
saveTask.Start();
}
当然,正如其他地方提到的,您需要确保 运行 异步调用尽可能多的异步,例如,如果您的应用程序中有一个保存按钮,您可以异步获取该事件,然后调用异步 PersistChangesAsync。
但是在我的应用程序启动时,我可能不希望在加载基本设置、验证用户或其他任何事情之前发生任何事情,然后你甚至可以使用 saveTask.RunSynchronously() (尽管很明显你仍然可以 运行 几个异步的子任务然后等待结果(如果有的话,或者在一切完成时定义一个延续任务)
我是 windows 的新手,我正在使用通用应用程序制作一个业余爱好项目。几天后,我发现连接串行端口的唯一方法是使用来自 SerialDevice class.
并与之相关的异步方法我喜欢关于该主题的一般性建议:一旦你开始使用一个序列号 api,那么从 'Main' 开始将整个应用程序转换为异步会容易得多(http://blog.stephencleary.com/2012/02/async-and-await.html ) 而不是处理与异步方法的同步调用相关的问题。
然而,由 VS2015 创建的通用应用程序包含大量生成的非异步代码,这些代码并不旨在被理解。我想在某个地方有一个通用模式可以处理这个问题,但我找不到它的任何踪迹。那我该怎么办呢?
通用应用程序未被“此应用程序是异步的”和“此应用程序不是异步的”分隔,创建async
方法 而不是 意味着您必须绝对更改所有内容才能使用它们。
async
和 await
的好处之一是允许您在不冻结 UI.
Stephen Cleary 的“异步所有事物”模式完全没有必要,它滥用了异步方法的目的。
大多数代码不需要用异步方法包装,同步方法几乎可以处理所有事情。然而,对于 long-运行 进程,例如从 Web 服务请求数据,最适合异步方法,因为它需要很长时间。
重要的是您不要沉浸在创建数百万个 async
方法的异常模式中,找出 需要 什么是异步的并实现此功能因此。
之所以有些UWP API是async
是因为有些进程不是瞬时的,调用async
API方法时要记住,您要求 操作系统 代表您执行操作。事实上,操作系统可能 就绪 ,或者可能超载,可能无法立即满足您的请求,因此这些方法是异步的,这确保您的应用程序不会等待一个请求。
我建议您阅读此 here。
I suppose there is a general pattern somewhere do deal with this issue but I could not find any trace of it. So what should I do?
我的建议总是这样:
- 从 "leaves" 开始并识别自然异步操作。对于您的情况,这很容易,因为在 Windows 通用平台中,自然异步操作 只有 具有异步 API。
- 使用
await
调用异步 API。 await
的存在将要求调用方法为async
(您应该将其 return 类型从void
更改为Task
或从T
到Task<T>
).- 此转换使调用方法异步,因此返回步骤 (2) 它是 个调用方。
- 重复直到找到 "root" 方法 - 在 Windows 通用应用程序中,这通常是一个事件处理程序,必须是
async void
(它们不允许是async Task
).
您可能 运行 通过您的代码库遇到 async
"grows" 等各种问题 - 例如,您不能在 属性 中使用 await
吸气剂或构造函数。我有一个 series of posts on my blog describing techniques to work around these problems.
这是新手混淆的结果。
一个。术语 'async function' 具有三个含义:
A.1。签名中有 'async' 项的函数。该术语的唯一意义是编译器不会将函数体中的 'await' 视为变量,而是将其视为 await 语句。它不会以任何其他方式更改签名,它严格用于向后兼容。
A.2。可以等待的任务类型的函数。
A.3。主体中也有 await 语句的 Task 类型的函数。
乙。 UI 处理未被 await 语句阻塞:如果来自 UI 基础设施的一个回调正在等待 await 语句,UI 消息处理仍在执行。
因此,为了从 UI 方法调用异步函数 (A.2):
(a) 将 'async' 项添加到 UI 函数签名 (A.1)。
(b) 在函数内部使用await语句调用异步库函数(A.2)
(c) 以一种或另一种方式处理异步执行的结果。
async-await 模式引起的最大困惑是该模式只不过是将一个函数包装在任务中,运行 它和 return 运行ning Task(理解这一点非常重要,因为您并不总是希望您的 Task 自动启动...)。
一旦您意识到这一点,就应该更容易理解任何异步调用都可以很容易地被这样的任务包装。
public void PersistChanges()
{
var saveTask = new Task(() => PersistChangesAsync());
saveTask.Start();
}
当然,正如其他地方提到的,您需要确保 运行 异步调用尽可能多的异步,例如,如果您的应用程序中有一个保存按钮,您可以异步获取该事件,然后调用异步 PersistChangesAsync。
但是在我的应用程序启动时,我可能不希望在加载基本设置、验证用户或其他任何事情之前发生任何事情,然后你甚至可以使用 saveTask.RunSynchronously() (尽管很明显你仍然可以 运行 几个异步的子任务然后等待结果(如果有的话,或者在一切完成时定义一个延续任务)