1. async/await 与同步方法的执行顺序
无论是使用 async/await 还是同步方法,它们的执行顺序是相同的,都是按照代码书写的顺序执行的。关键的区别在于 异步方法执行时不会阻塞线程,而同步方法会阻塞线程。
代码执行顺序:
- 同步方法:代码按照顺序执行,遇到耗时操作时(如 I/O 操作、网络请求等),整个线程会被阻塞,直到操作完成后,继续执行后续代码。
- 异步方法 (
async/await):代码同样是按顺序执行的,但在遇到await时,异步方法会挂起并将控制权交还给调用线程,等待异步操作完成,不会阻塞线程。一旦异步操作完成,方法会恢复执行后续代码。
2. 同步方法(会阻塞线程)
同步方法会直接阻塞当前线程,直到执行完当前操作。比如,如果你调用了一个网络请求的同步方法,线程会一直等待,直到请求完成,才继续执行后续代码。
示例:
public OperateResult CommandEx(EnumCommand command, bool someFlag)
{
// 假设这是一个同步的长时间操作(比如网络请求、文件读取等)
SomeLongOperation(); // 这会阻塞当前线程
return new OperateResult { IsSuccess = true }; // 返回结果
}
- 在这种情况下,
SomeLongOperation()执行时,当前线程(通常是主线程)会被阻塞,不能执行其他操作。 - 直到
SomeLongOperation()执行完成,才会继续执行return new OperateResult { IsSuccess = true };。
3. 异步方法(不会阻塞线程)
异步方法使用 async/await 后,执行时会让出控制权给调用线程,异步操作(如 SomeAsyncOperation())执行时不会阻塞当前线程。
示例:
public async Task<OperateResult> CommandEx(EnumCommand command, bool someFlag)
{
// 假设这是一个异步的长时间操作(比如网络请求、文件读取等)
await SomeAsyncOperation(); // 这里不会阻塞线程
return new OperateResult { IsSuccess = true }; // 返回结果
}
- 在这种情况下,
SomeAsyncOperation()被await后,异步操作开始执行,但 不会阻塞当前线程。 - 当
SomeAsyncOperation()执行时,主线程可以继续做其他事情(比如响应用户界面事件或处理其他请求)。 - 等到
SomeAsyncOperation()完成后,await语句会恢复方法的执行,继续执行后面的代码return new OperateResult { IsSuccess = true };。
总结:
- 同步方法:会阻塞当前线程,直到操作完成。例如,执行一个耗时的网络请求时,线程会一直等待,不能处理其他操作。
- 异步方法:使用
async/await后,异步操作不会阻塞线程。线程可以继续执行其他任务,直到异步操作完成后,才会恢复执行后续代码。
关键区别:
- 阻塞:同步方法会阻塞线程,异步方法不会阻塞线程。
- 线程利用:异步方法利用线程空闲时间来执行其他任务,而同步方法需要等待任务完成才能继续。
这就是 async/await 和同步方法的主要差异。async/await 使得应用程序更加高效,特别是在处理 I/O 密集型操作时,可以避免主线程被阻塞,提高应用的响应能力。
代码补充:
4.1同步方法代码:
public class DataFetcher
{
// 模拟同步操作,发起一个网络请求并等待结果
public string FetchDataSync(string url)
{
// 模拟长时间的网络请求(例如,HTTP 请求)
var result = SomeLongNetworkRequest(url); // 同步操作,阻塞线程
return result;
}
// 模拟一个同步的网络请求操作(实际上是阻塞的)
private string SomeLongNetworkRequest(string url)
{
// 这里模拟的网络请求实际上是阻塞的
System.Threading.Thread.Sleep(5000); // 假装等待了 5 秒钟
return "Server Response";
}
}
在上面的同步方法中,SomeLongNetworkRequest() 会 阻塞当前线程,直到网络请求完成。整个过程需要 5 秒钟,期间主线程不能做其他事情。
4.2异步方法代码:
public class DataFetcher
{
// 模拟异步操作,发起一个网络请求并等待结果
public async Task<string> FetchDataAsync(string url)
{
// 使用异步方法来发起网络请求
var result = await SomeLongNetworkRequestAsync(url); // 异步操作,不阻塞线程
return result;
}
// 模拟一个异步的网络请求操作(实际上是非阻塞的)
private async Task<string> SomeLongNetworkRequestAsync(string url)
{
// 异步操作,不会阻塞线程
await Task.Delay(5000); // 模拟等待 5 秒钟(例如网络延迟)
return "Server Response";
}
}
//2.异步方法调用
public class Program
{
public static async Task Main()
{
var fetcher = new DataFetcher();
Console.WriteLine("Fetching data asynchronously...");
// 调用异步方法
string data = await fetcher.FetchDataAsync("https://example.com");
// 数据获取完成后
Console.WriteLine("Data fetched: " + data);
}
}
在异步方法中,SomeLongNetworkRequestAsync() 使用 await 关键字,这意味着 异步操作 会释放当前线程,并且不阻塞主线程。即使网络请求还没有完成,主线程也可以继续执行其他任务,而一旦网络请求完成,await 会继续执行并返回结果。
4.3. 对比分析
-
同步方法:
- 主线程在执行
SomeLongNetworkRequest()时会被 阻塞,无法继续执行其他任务,直到请求完成。 - 如果网络请求时间长,主线程可能需要等待较长时间(例如 5 秒钟)。
- 主线程在执行
-
异步方法:
-
当你调用
FetchDataAsync时:- 主线程开始执行
FetchDataAsync,并遇到await SomeLongNetworkRequestAsync(url),此时 主线程解放,去执行其他不同方法体内的方法的操作(比如 UI 更新方法)。 -
当第一个请求完成后,控制权返回到
await后面的位置,执行后续代码,即打印“First request completed”,然后继续执行第二个异步请求。 -
异步操作是 顺序执行的,第二个请求在第一个请求完成后才会开始。
- 当请求完成时,
await会恢复并继续执行后面的代码,整个过程不会影响主线程的其他任务。
- 主线程开始执行
4.4. 总结:
- 同步方法适用于不涉及 I/O 操作或耗时任务较短的场景。它简单,但会 阻塞线程,导致性能瓶颈。
- 异步方法则适用于 I/O 密集型任务,能够提高程序的 响应性,特别是在需要等待外部资源(如网络、数据库等)的情况下,不会造成主线程阻塞。
async await-- 异步调用,顺序执行,解放主线程,await之后的方法是一个Task类型的异步方法(I/O操作密集型耗时方法)

855

被折叠的 条评论
为什么被折叠?



