一、简介
使用TaskPool/Worker必然涉及到跨线程传输数据,对象/方法在跨线程传递时需要序列化和反序列化。当对象本身较大且结构复杂时,序列化/反序列化的耗时就会增加,从而影响应用运行的整体性能。DevEco Profiler的Anomaly泳道可以检测序列化和反序列化的耗时,通过ArkTS Callstack泳道定位到序列化/反序列化耗时代码,使用Sendable,提升应用性能。本文会以具体的案例介绍如何使用DevEco Profiler检测序列化和反序列化的耗时。
二、序列化/反序列化性能检测
class Message {
id: string = '';
title: string = '';
content: string = '';
constructor(id: string, title: string, content: string) {
this.id = id
this.title = title
this.content = content
}
}
const messages = new Array<Message>()
for (let i = 0; i < 300000; i++) {
const message = new Message(`消息${i}`, `这是一条点赞消息:${i}`, `张三点赞了你:${i}`)
messages.push(message)
}
// 将30万条数据传递给子线程
const task = new taskpool.Task(post, messages)
taskpool.execute(task)
@Concurrent
function post(messages: Array<Message>) {
for (let i = 0; i < messages.length; i++) {
const msg = messages[i]
console.log(`${msg.id},${msg.title},${msg.content}`)
}
}
如上代码,构建30万条数据,将数据传递给子线程,跨线程传输数据会触发序列化和反序列化。我们使用上面的代码来检测序列化和反序列化的耗时。
- 打开DevEco Studio,确认设备已连接,待录制应用已安装。
- 启动应用,点击Profiler,选择Frame模板,选择当前应用进程,点击Create Session。
- 在录制之前,可以设置序列化/反序列化的阈值,如下图所示。
- 开始录制,录制过程中可正常操作应用。
当Profile分析完成后,就能在Anomaly泳道上看到序列化/反序列化的耗时。
如下图所示,查看详细信息。
当发生序列化/反序列化耗时问题,通过下图的步骤就可以定位到耗时代码。
2、1 修复问题
为了解决该问题,需要使用@Sendable注解,如下代码,只需在Message类加上@Sendable注解,其它代码不用改。
// 加上@Sendable注解即可
@Sendable
class Message {
id: string = '';
title: string = '';
content: string = '';
constructor(id: string, title: string, content: string) {
this.id = id
this.title = title
this.content = content
}
}
优化后再次通过序列化超时检测工具检测录制,发现该场景下序列化耗时已小于默认阈值(8ms),在Anomaly泳道中已经没有对应超时的Trace点。跨线程传输数据量较大时,使用Sendable引用传递方式可以有效减少序列化耗时,提升应用性能。
为什么使用Sendable后,跨线程传输数据就不耗时了呢?因为Sendable对象分配在共享堆中,可以在不同并发实例间通过引用传递。通过引用传递方式传输对象相比序列化方式更加高效,同时不会丢失类上携带的成员方法。更多关于Sendable的介绍,可查看鸿蒙多线程并发。