一、鸿蒙应用开发涉及的并发问题
并发是指在同一时间段内,能够处理多个任务的能力。为了提升应用的响应速度与帧率,以及防止耗时任务对主线程的干扰,HarmonyOS系统提供了异步并发和多线程并发两种处理策略。
1、异步并发:
异步并发是指异步代码在执行到一定程度后会被暂停,以便在未来某个时间点继续执行,这种情况下,同一时间只有一段代码在执行。
2、多线程并发
多线程并发允许在同一时间段内同时执行多段代码。在主线程继续响应用户操作和更新UI的同时,后台也能执行耗时操作,从而避免应用出现卡顿。
-
说明:对鸿蒙应用开发多线程,以及进程等知识不了解的朋友可以参考我之前的文章【最新鸿蒙应用开发总结】——多线程?并发模型?一篇看懂(建议收藏)-CSDN博客,接下来我主要探讨的是异步并发的一些相关问题。
并发能力在多种场景中都有应用,其中包括单次I/O任务、CPU密集型任务、I/O密集型任务和同步任务等。开发者可以根据不同的场景,选择相应的并发策略进行优化和开发。ArkTS支持异步并发和多线程并发。
-
Promise和async/await提供异步并发能力,适用于单次I/O任务(不了解可以参考我之前的文章)的开发场景。(网络请求、磁盘读写、数据库查询,用户输入等)
-
TaskPool和Worker提供多线程并发能力,适用于CPU密集型任务、I/O密集型任务和同步任务等并发场景。
二、开启多线程并发和使用异步并发的区别?或者说什么时候用哪种?结合使用场景;
-
概念上的区别:
taskpool开辟子线程能够充分利用现代手机设备多核配置,提高程序的并发性和运行效率;它是通过多线程异步,是通过调用线程池内的线程去异步完成任务。
Promise是在当前线程进行异步调用,可以避免阻塞主线程,保证程序的响应速度,提高用户体验;其实是同一个线程在各个任务间进行切换,通过暂时挂起任务实现异步 ,异步代码会被挂起并在之后继续执行,并且同一时间只有一段代码执行。
-
具体使用场景上的区别:
1、当需要执行I/O操作时,使用异步操作比使用线程+同步I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.Net Remoting等跨进程的调用。
2、当需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行时,建议使用子线程操作,还有一些CPU密集型任务、I/O密集型任务和同步任务等场景,不了解的朋友可以参考我之前的文章。
三、异步并发考虑的问题(总结)
服务端响应数据慢怎么解决?有哪些原因?如何考虑优化?
服务端响应整个流程慢可能有多个原因,这需要进行系统性的性能分析以确定根本原因。以下是一些可能导致服务端响应慢的常见原因:
-
网络延迟: 如果服务端与客户端之间的网络延迟较高,数据在两者之间传输的时间将会增加。
-
服务器性能不足: 服务器硬件性能不足,或者服务器资源(CPU、内存、磁盘)被过度占用,可能导致响应时间延迟。
-
数据库性能: 如果应用程序需要从数据库中检索大量数据,或者数据库查询性能较差,会导致响应时间延迟。优化数据库查询、使用索引、缓存等可以改善这方面的问题。
-
第三方服务延迟: 如果应用程序依赖于外部的第三方服务,而这些服务的响应速度较慢,也会影响整体的响应时间。
-
未优化的代码: 代码的性能问题可能导致响应时间延迟。循环次数过多、未经优化的算法、内存泄漏等都可能影响代码的性能。
-
未优化的资源: 大量未经优化的静态资源(如图片、CSS、JavaScript)可能导致页面加载慢,从而影响整体的用户体验。
-
缺乏合适的缓存机制: 缺乏适当的缓存机制可能导致相同的请求重复执行相同的计算,增加响应时间。
为了准确定位服务端响应慢的原因,可以使用性能分析工具、日志分析工具以及监控工具进行详细的诊断。系统性的性能测试和监控可以帮助发现瓶颈,从而采取相应的优化策略。
服务端响应期间会不会卡页面渲染?
HarmonyOS(鸿蒙)是一个分布式操作系统,与传统的 Web 开发有所不同。在 Web 开发中,服务端响应慢可能会导致页面在浏览器中渲染时出现卡顿,因为浏览器通常会在主线程上执行 JavaScript 代码,包括处理响应数据和更新 DOM。
对于 HarmonyOS,服务端响应慢不会直接导致页面渲染的卡顿,因为 HarmonyOS 应用通常是本地应用,而不是在浏览器中运行的 Web 应用。HarmonyOS 应用的渲染通常是在本地设备上进行的,与服务端响应的速度关系不大。
但是,在 HarmonyOS 应用中,如果你的应用在进行网络请求时阻塞了主线程,例如在主线程上进行了同步的网络请求,那么这可能会导致 UI 的卡顿。因此,建议在进行网络请求时使用异步的方式,以避免阻塞主线程。
总体而言,HarmonyOS 应用的响应速度主要与本地设备的性能和网络请求的优化有关,与服务端响应慢是否会卡页面渲染关系较小。在应用开发中,建议合理使用异步操作、优化网络请求和合理设计本地业务逻辑,以提供更好的用户体验。
异步方法Promise,callback,promise是在哪个线程? 是否会卡主线程?实际开发中会优先使用哪种方式做回调?await是否会卡线程?
Promise是在主线程执行的,不会卡主线程,是一种异步编程方式,用于处理异步操作。
await 不会卡线程,await 关键字会暂停当前异步函数的执行,并将控制权交还给事件循环,直到promise对象解析或拒绝。
通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。
优先使用promise。
promise如何使用?会不会阻塞UI线程?Async await ,await是否阻塞线程?(可了解下底层实现逻辑)
Promise 是 JavaScript 中用于处理异步操作的一种机制,它提供了更优雅的方式来处理异步代码,避免了回调地狱 。
-
使用new Promise() 创建
Promise
对象。 -
处理成功和失败,在执行器函数中进行异步操作,根据结果调用
resolve
或者reject
。 -
使用
then
和catch
处理结果,使用then
处理成功的情况,使用catch
处理失败的情况。
Promise不会阻塞UI线程,Promise设计的目的之一就是避免阻塞主线程。异步操作的执行不会阻塞 UI 线程,而是通过事件循环机制在后台执行。当异步操作完成后,它会调用相应的 resolve
或 reject
,然后触发注册的 then
或 catch
处理程序。
async/await
是 JavaScript 中处理异步代码的一种方式,它建立在 Promise 基础之上,提供了更清晰和易读的语法。使用 await
关键字可以暂停异步函数的执行,等待 Promise 对象的解决(resolve)。
await
并不会阻塞整个线程。当遇到 await
时,它会让出线程的执行,使得其他任务可以继续执行。在背后,await
会暂停当前函数的执行,等待 Promise 对象的状态发生变化。
promise如何解决异步并发?promise异步并发遇到的场景有什么?(Promise并发控制的实现方式)
异步并发涉及同时执行多个异步操作。可以使用 Promise.all
或 Promise.allSettled
方法来处理多个异步操作的并发执行。
-
使用
Promise.all
处理异步并发:Promise.all
接收一个 Promise 数组,返回一个新的 Promise,该新 Promise 在数组中的所有 Promise 都成功解析后才会被解析,或者在数组中的任何一个 Promise 被拒绝时被拒绝。 -
使用
Promise.allSettled
处理异步并发:Promise.allSettled
与Promise.all
类似,但它不会在任何一个 Promise 被拒绝时立即拒绝,而是会等待所有 Promise 完成,无论成功还是失败,都会解析返回一个包含所有 Promise 状态的结果数组。
在一些场景,比如并行请求多个资源的情况: 当需要同时获取多个资源时,可以使用Promise.all()方法将多个Promise对象包装成一个新的Promise对象,以便等待它们全部完成。
参考链接:Promise异步并发控制Promise 异步并发控制-JavaScript中文网-JavaScript教程资源分享门户
then调用和await调用的区别
当使用Promise进行异步操作时,可以使用.then和await两种方式来调用异步接口;.then调用不阻塞当前线程,异步回调结束后会直接走到then中,await会等待当前异步方法执行结束才会继续往下执行。
.then是promise接口的一个属性,可以通过.then方法链式的添加回调函数处理结果。
await是一个语法糖,是将后面的代码暂时挂起,等到任务执行完成后再继续执行。
- 在语法结构上也有不同:.then是通过方法链式调用处理Promise的结果,而await是异步函数内使用的关键字。
- 在处理错误的方式不同:.then是通过.catch方法来捕获Promise的拒绝结果,而await是通过try/catch块来捕获异步操作中的错误。
- 执行的顺序也不同:.then中的回调函数会在Promise完成后按顺序执行,而await会暂停当前函数的执行,直到等待Promise的解决或者拒绝。
异步提交,代码封装 (Promise如何使用,有几种是否用方式,分别是什么?)
-
then().catch()
-
async/await+try{}catch(){}
异步提交(例如异步请求提交数据),可以封装一个函数来处理异步操作,使用 Promise 或者 async/await 提供异步编程的支持。
-
使用
Promise
封装异步提交:function asyncSubmit(data) { return new Promise((resolve, reject) => { // 模拟异步提交 setTimeout(() => { const success = true; // 模拟提交成功 if (success) { resolve('提交成功'); } else { reject('提交失败'); } }, 1000); }); } // 调用异步提交 asyncSubmit({ /* 数据 */ }) .then((result) => { console.log(result); }) .catch((error) => { console.error(error); });
-
使用async/await封装异步提交:
async function asyncSubmit(data) { return new Promise((resolve, reject) => { // 模拟异步提交 setTimeout(() => { const success = true; // 模拟提交成功 if (success) { resolve('提交成功'); } else { reject('提交失败'); } }, 1000); }); } // 调用异步提交 async function submit() { try { const result = await asyncSubmit({ /* 数据 */ }); console.log(result); } catch (error) { console.error(error); } } submit();