1.parallelStream 基本原理
2.TerminateProcess HOOK
3.功能更新生成源码异步下载,任务任务让系统响应速度提升10倍
4.Matrix卡顿优化之IdleHandlerLagTracer源码分析
5.利用Cython加速计算密集型python任务
parallelStream 基本原理
stream流是列表java在jdk1.8中引入的工具,旨在简化任务处理,源码源码让我们专注于实现细节,任务任务而无需关注任务调度,列表由stream自动实现调度。源码源码劫持lsp源码例如,任务任务如果我们需要对列表进行求和,列表只需通过列表生成流,源码源码使用reduce方法传递表达式即可,任务任务省去了for循环和if判断等繁琐操作。列表默认情况下,源码源码stream是任务任务单线程执行的。
对于需要并行执行的列表场景,例如同时计算多个任务结果,源码源码java提供了parallelStream。通过parallelStream,可将上述例子中先计算1+2,再计算3+3的方式,优化为同时计算1+2和3+3,利用处理器的多核性能提升效率。parallelStream内部通过ForkJoinPool的commonPool线程执行任务,大大简化了并行编程的复杂性。
探究parallelStream如何利用ForkJoinPool,首先,integers.parallelStream()返回Stream对象,parallel属性为true,表明这是招商加盟网站源码 厦门并行流。接下来,调用stream.reduce方法处理流。在reduce()源码中,它主要通过调用evaluate()方法处理流。evaluate()首先检查linkedOrConsumed属性,确保流未被消费。对于并行流,evaluate()创建ReduceTask,并通过其invoke方法执行计算。
ReduceTask是ForkJoinTask的子类,它不重写invoke方法,因此调用ReduceTask.invoke()等同于调用ForkJoinTask.invoke()。这样,parallelStream通过ForkJoinTask实现了并行流处理,具体通过递归任务分解和并行执行实现。
TerminateProcess HOOK
å¦ä½ä¿è¯èªå·±çç¨åºä¸è¢«å ³éï¼
å°±ç®æ¯ä¸äºè¿ç¨è½¯ä»¶ä¹ä¸å¯ä»¥å ³é
samba æå¬è¿æ人éç¨ç¨åºäºç¸çæ§çæ¹æ³æ¥è¾¾å°ç®çã
ä½è¿æ ·å°±ä¼å ç¨ç³»ç»èµæºãä¸ä¸ªä¸å ä»ä¹æ§ä»¶ç纯çªä½é½è¦3å ç¨MBå åï¼
å¦æå ä¸ææ¬æ¥çé£ä¸ªç¨åºï¼å²ä¸æ¯è¦å å»åå MBå åï¼è¿å¯¹äºæé£ä¸ªå°ç¨åºæ¥è®²ä¸ä¸å¯å¿åçã
请é®æä»ä¹æ¯è¾å¥½çæ¹æ³å¯ä»¥è§£å³ï¼æè¿æ¹é¢çæ§ä»¶åï¼å è°¢è¿å¤§å®¶äºï¼
---------------------------------------------------------------
å¨WINDOWSæä½ç³»ç»ä¸ï¼å½æ们æ æ³ç»ææè ä¸ç¥éææ ·ç»æä¸ä¸ªç¨åºçæ¶åï¼æè æ¯æå¾å»æ¾âéåºâæé®çæ¶åï¼é常ä¼æâCTRL+ALT+DELâå¼åºä»»å¡ç®¡çå¨ï¼æ¾å°æ³ç»æçç¨åºï¼ç¹ä¸ä¸âç»æä»»å¡âå°±äºäºäºï¼åµåµï¼è½ç¶æç¹ç²é²ï¼ä½å¤§å¤æ°æ åµä¸é½å¾ææï¼ä¸æ¯åï¼
设æ³ä¸ä¸ï¼å¦ææè¿ä¹ä¸ç§è½¯ä»¶ï¼å®æè¦åçå·¥ä½å°±æ¯å¯¹æ个使ç¨è å¨æå°çµèä¸çæ´»å¨ä½ä¸å®çéå¶ï¼èåä¸è½è¢«ä½¿ç¨è éè¿âç»æä»»å¡âè¿ç§æ¹å¼è½»æå°è§£é¤éå¶ï¼é£è¯¥æä¹åï¼æ éæè¿ä¹ä¸ç§æ¹æ³ï¼1.å±è½âCTRL+ALT+DELâè¿ä¸ªçé®çç»åï¼2.让ç¨åºä¸åºç°å¨ä»»å¡ç®¡çå¨çå表ä¹ä¸ï¼3.让任å¡ç®¡çå¨æ æ³ææè¿ä¸ªä»»å¡ã对äºç¬¬ä¸ç§æ¹æ³ï¼è¿æ ·æªå ä¹å¤ªæ®é ·äºï¼ç¨æ¯äºâç»æä»»å¡âè¿ç§æ¹æ³ç人ä¼å¾ä¸ä¹ æ¯çï¼å¯¹äºç¬¬äºç§æ¹æ³ï¼å¨WINDOWS 9Xä¸å¯ä»¥å¾è½»æå°ä½¿ç¨æ³¨åæå¡è¿ç¨çæ¹æ³å®ç°ï¼ä½æ¯å¯¹äºWINDOWS NTæ¶æçæä½ç³»ç»æ²¡æè¿ä¸ªæ¹æ³äºï¼è¿ç¨å¾é¾è身ï¼è½ç¶ä»ç¶å¯ä»¥å®ç°éèï¼ä½å®ç°æºå¶è¾ä¸ºå¤æï¼å¯¹äºç¬¬ä¸ç§æ¹æ³ï¼å®ç°èµ·æ¥æ¯è¾ç®åï¼æçä½åï¼IPGate ç½åè¿æ»¤å¨ å°±æ¯éç¨çè¿ç§æ¹å¼é²æçï¼æ¥ä¸æ¥æå°±æ¥ä»ç»è¿ç§æ¹æ³ã
ä»»å¡ç®¡çå¨çâç»æä»»å¡âå®é ä¸å°±æ¯å¼ºå¶ç»æ¢è¿ç¨ï¼å®æ使ç¨çææéæ¯ä¸ä¸ªå«åTerminateProcess()çWin APIå½æ°ï¼æ们æ¥ççå®çå®ä¹ï¼
BOOL TerminateProcess(
HANDLE hProcess; // å°è¢«ç»æè¿ç¨çå¥æ
UINT uExitCode; // æå®è¿ç¨çéåºç
);
çå°è¿éï¼æ¯ä¸æ¯è§å¾ä¸å¿ å¾ä¸çé½ç¥éæ¥ä¸æ¥è¦åä»ä¹ï¼Hook TerminateProcess()å½æ°ï¼æ¯æ¬¡TerminateProcess()被è°ç¨çæ¶åå å¤æä¼å¾ç»æçè¿ç¨æ¯å¦æ¯æçè¿ç¨ï¼å¦ææ¯çè¯å°±ç®åå°è¿åä¸ä¸ªé误ç å°±å¯ä»¥äºãççæ¯è¿ä¹ç®ååï¼å æåºä¸ä¸ªé®é¢ï¼å¦ä½æ ¹æ®hProcesså¤æå®æ¯å¦æ¯æçè¿ç¨çå¥æï¼çæ¡æ¯ï¼å¨æçè¿ç¨å½ä¸å è·å¾æçè¿ç¨çå¥æï¼ç¶åéè¿è¿ç¨é´é讯æºå¶ä¼ éç»é©åå½æ°ï¼ä¸hProcessè¿è¡æ¯è¾ä¸å°±è¡äºï¼éï¼å 为å¥ææ¯ä¸ä¸ªè¿ç¨ç¸å ³çå¼ï¼ä¸åè¿ç¨ä¸å¾å°çæçè¿ç¨çå¥æçå¼å¨è¿ç¨é´è¿è¡æ¯è¾æ¯æ æä¹çã
æä¹åï¼æ们æ¥èå¯ä¸ä¸æçhProcesså®æ¯å¦ä½å¾å°çãä¸ä¸ªè¿ç¨åªæå®çè¿ç¨IDæ¯ç¬ä¸æ äºçï¼æä½ç³»ç»éè¿è¿ç¨IDæ¥æ è¯ä¸ä¸ªè¿ç¨ï¼å½æ个ç¨åºè¦å¯¹è¿ä¸ªè¿ç¨è¿è¡è®¿é®çè¯ï¼å®é¦å å¾ç¨OpenProcessè¿ä¸ªå½æ°å¹¶ä¼ å ¥è¦è®¿é®çè¿ç¨IDæ¥è·å¾è¿ç¨çå¥æï¼æ¥ççå®çåæ°ï¼
HANDLE OpenProcess(
DWORD dwDesiredAccess, // å¸æè·å¾ç访é®æé
BOOL bInheritHandle, // æææ¯å¦å¸ææè·å¾çå¥æå¯ä»¥ç»§æ¿
DWORD dwProcessId // è¦è®¿é®çè¿ç¨ID
);
èç»æ¸æ¸æ¾ç°ï¼å¨è°ç¨TerminateProcess()ä¹åï¼å¿ å è°ç¨OpenProcess()ï¼èOpenProcess()çåæ°è¡¨ä¸çdwProcessIdæ¯å¨ç³»ç»èå´å å¯ä¸ç¡®å®çãå¾åºç»è®ºï¼è¦Hookçå½æ°ä¸æ¯TerminateProcess()èæ¯OpenProcess()ï¼å¨æ¯æ¬¡è°ç¨OpenProcess()çæ¶åï¼æ们å æ£æ¥dwProcessIdæ¯å¦ä¸ºæçè¿ç¨çID(å©ç¨è¿ç¨é´é讯æºå¶)ï¼å¦ææ¯çè¯å°±ç®åå°è¿åä¸ä¸ªé误ç å°±å¯ä»¥äºï¼ä»»å¡ç®¡çå¨æ¿ä¸å°æçè¿ç¨çå¥æï¼å®å¦ä½ç»ææçè¿ç¨å¢ï¼
è³æ¤ï¼çå¢å ¨é¨æå¼äºãç±Hook TerminateProcess()å°Hook OpenProcess()çè¿ä¸ªè¿ç¨ï¼ä½ç°äºä¸ä¸ªéåæç»´çææ³ãå ¶å®æå½åé»è¿äºTerminateProcess()çæ»è¡åéå天åºä¹ä¸æ¥ï¼ä½æç»è¿æ¯è¹¦åºäºçµæçç«è±ï¼æ³¨æå转移å°äºOpenProcess()ä¸é¢ï¼å®ç°äºè¿ç¨é²æãåæ¦ä¹ä½ï¼å°è¿å¿å¾ä½ä¼æ¿åºæ¥ä¸å¤§å®¶å享ã
---------------------------------------------------------------
è¦ä¸æç»ä½ ææçå¯æ§è¡æ件çæºä»£ç åå¨æè¿æ¥åºåç»ä½ 好äº
å¨æè¿æ¥åºä½ èªå·±å¯ä»¥æ¢æ
å°±æ¯è¦æ³¨å ¥çé£ä¸ª
ï¼æ³¨å ¥å°çç®æ ç¨åºä½ èªå·±è®¾ç½®
---------------------------------------------------------------
åµåµï¼ææåå®ç°äºï¼ï¼
éè¿setwindowshookex建ç«CBTçHookï¼Hook DLLä¸å è½½APIéå®åï¼å°±å¯ä»¥è¾¾å°å ¨å±ææçAPIHOOKææäºï¼è¿è¦å¯¹MapFileæä½ï¼ä»¥ä¾¿ç»ä¸å ¨å±çåæ°
ä¸è½½å°åï¼/lysoft/projects/API Hook.rar
by Liu Yang
---------------------------------------------------------------
ä¸é¢çä¾åï¼å¾å害çï¼ä¸åªæ¯ä»»å¡ç®¡çå¨ï¼è¿å«ç第ä¸æ¹è½¯ä»¶é½å¥ä½ä¸å¾ï¼
ç¦æ¢ CTRL+ALT+DELETE under XP and Win, çæ¹æ³ï¼ä¸è¿å®¹æç ´è§£
å¦å¤ï¼XPä¸Ginaæ¹æ³æ¯ä¸è¡çï¼ææä¾çDemo就没é®é¢äºãè³äºé£ä¸ªDLLæ¯æä¹åçï¼å°±ä¸ä¾¿å ¬å¼äºãè°ç¨æ¥å£å°±å¨ä»£ç ä¸ï¼åµåµï¼è±äºæ3天å夫ææ好ãæç¹ç´¯äºï¼ä¼æ¯äºã
procedure DisableTaskMgr(bTF: Boolean);
var
reg: TRegistry;
begin
reg := TRegistry.Create;
reg.RootKey := HKEY_CURRENT_USER;
reg.OpenKey('Software', True);
reg.OpenKey('Microsoft', True);
reg.OpenKey('Windows', True);
reg.OpenKey('CurrentVersion', True);
reg.OpenKey('Policies', True);
reg.OpenKey('System', True);
if bTF = True then
begin
reg.WriteString('DisableTaskMgr', '1');
end
else if bTF = False then
begin
reg.DeleteValue('DisableTaskMgr');
end;
reg.CloseKey;
end;
// Example Call:
procedure TForm1.Button1Click(Sender: TObject);
begin
DisableTaskMgr(True);
end;
---------------------------------------------------------------
type //å®ä¹ä¸ä¸ªå ¥å£ç»æ
PImage_Import_Entry = ^Image_Import_Entry;
Image_Import_Entry = record
Characteristics: DWORD; //"code"or"data"or"bss"
TimeDateStamp: DWORD;
MajorVersion: Word;
MinorVersion: Word;
Name: DWORD; //æå±å¨æåºæç¨åºçå称
LookupTable: DWORD;
end;
type //å®ä¹ä¸ä¸ªè·³è½¬çç»æ
TImportCode = packed record
JumpInstruction: Word; //å®ä¹è·³è½¬æ令jmp
AddressOfPointerToFunction: ^Pointer; //å®ä¹è¦è·³è½¬å°çå½æ°
end;
PImportCode = ^TImportCode;
implementation
//è¿åå½åå½æ°å°å
function LocateFunctionAddress(Code: Pointer): Pointer;
var
func: PImportCode;
begin
Result := Code;
if Code = nil then exit;
try
func := code;
if (func.JumpInstruction = $FF) then
begin
Result := func.AddressOfPointerToFunction^;
end;
except
Result := nil;
end;
end;
//æ¹åå½æ°çæå
function RepointFunction(OldFunc, NewFunc: Pointer): Integer;
var
IsDone: TList;
//å°æå®å®ä¾ä¸çå¼å ¥å½æ°å®ä½ä¸ºæ°å½æ°
function RepointAddrInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
var
Dos: PImageDosHeader;//dos head
NT: PImageNTHeaders; //nt head
ImportDesc: PImage_Import_Entry; //å½æ°å ¥å£å°å
RVA: DWORD;
Func: ^Pointer;
DLL: string;
f: Pointer;
written: DWORD;
begin
Result := 0;
Dos := Pointer(hModule);//å®ä¾å¥æ
if IsDone.IndexOf(Dos) >= 0 then exit; //æ¯å¦å·²ç»æ¿æ¢è¿æ¤å®ä¾å¥æ
IsDone.Add(Dos); //æ·»å å®ä¾å¥æ
OldFunc := LocateFunctionAddress(OldFunc);
if IsBadReadPtr(Dos, SizeOf(TImageDosHeader)) then exit;
if Dos.e_magic <> IMAGE_DOS_SIGNATURE then exit;//å¤ææ¯å¦æ¯åæ³çdos头
NT := Pointer(Integer(Dos) + dos._lfanew);//å¾å°pe头
//å¾å°è¾å ¥å½æ°çç¸å ³èå°å
RVA := NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if RVA = 0 then exit;
//计ç®å®é 第ä¸ä¸ªè¾å ¥å½æ°å°å
ImportDesc := pointer(integer(Dos) + RVA);
while (ImportDesc^.Name <> 0) do
begin
//å¾å°è¾å ¥çå¨æåºå称
DLL := PChar(Integer(Dos) + ImportDesc^.Name);
//éå½å°å¦ä¸ä¸ªå¨æåº
RepointAddrInModule(GetModuleHandle(PChar(DLL)), OldFunc, NewFunc);
//计ç®å¼å ¥å½æ°å¨ç¨åºä¸çè°å ¥å°å
Func := Pointer(Integer(DOS) + ImportDesc.LookupTable);
while Func^ <> nil do
begin
f := LocateFunctionAddress(Func^);
//æ¾å¯»å¼å ¥çå½æ°
if f = OldFunc then
begin
//æ³¨å ¥æ°å½æ°å°å
WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
if Written > 0 then Inc(Result);
end;
Inc(Func);
end;
Inc(ImportDesc);
end;
end;
begin
IsDone := TList.Create;
try
Result := RepointAddrInModule(GetModuleHandle(nil), OldFunc, NewFunc);
finally
IsDone.Free;
end;
end;
功能更新生成源码异步下载,让系统响应速度提升倍
通过本次优化更新,系统在生成源码、流程执行轨迹展示、SQL修改提示、系统函数的jar包定义、运维API依赖JAR包的引入、以及定时任务jar包的管理上,采用了异步操作模式,显著提升了系统响应速度与性能。下面详细解读各项功能的优化点和操作流程。1. 生成源码异步下载优化
优化后,手机dts源码输出方法生成源码时将采用异步下载策略。操作流程如下:点击项目卡片的“设置按钮”并选择“生成源码”。
在弹出的二次提示框中,选择是否携带JAR包,确认后点击“确定”。
再次点击项目卡片上的“设置按钮”进入“源码记录”。
在源码记录列表中可实时查看生成状态,生成完成后即可下载源码包。
若生成失败,点击操作栏的“详情”按钮查看具体原因。
2. 流程执行轨迹变量展示优化
优化后的流程执行轨迹功能,不仅能显示当前组件信息,还支持查看流程中其他组件的详细信息。系统变量信息被分类为入口参数、局部变量、配置组参数和基础参数,便于用户快速了解组件执行结果和变量值。3. 修改SQL使用提示优化
当SQL信息被接口引用时,修改SQL后系统将弹出提示,要求在接口中重新选择该SQL信息后才能生效。删除SQL时,系统会提示已引用的接口,需先去除引用后才能执行删除操作。4. 系统函数jar包定义为扩展jar包优化
系统将一些常用函数定义为扩展jar包,仅在需要时自动加载,减少执行引擎包体积,提升性能。棋牌游戏源码缺少苹果包以“SysFun_Feidai_BaseUtilsBaseUtils”为例,进行加载与使用。5. 运维API依赖JAR包引入优化
监控检测扩展jar包在本地客户端和执行引擎中使用时,需下载并安装后才能进行指标监控。操作包括下载、解压、配置,以及启动本地客户端等步骤。6. 定时任务jar包定义优化
定时任务jar包已整合至扩展jar包中,新增定时任务时系统会自动加载。用户也可提前手动添加,确保定时任务与项目部署包一同打包。 通过这些优化,系统响应速度得到显著提升,操作流程更加高效便捷。有兴趣的用户可申请免费试用体验。 SoFlu软件机器人,作为全球首款针对微服务架构的软件机器人,革新了传统编码作业模式,通过可视化拖拽与参数配置实现复杂业务逻辑,一人全栈解决后端、前端、测试、运维等各类工作需求,大幅度降低软件开发门槛,显著提升企业软件开发效率与生产力。 通过引入自动化、违规标题检测小程序源码标准化与工具化流程,SoFlu软件机器人解决了传统软件开发过程中的依赖人工、成本高昂、技术选型难等问题,突破了被国外开发工具“卡脖子”的技术壁垒,为企业软件开发带来了十倍效率提升。Matrix卡顿优化之IdleHandlerLagTracer源码分析
IdleHandler是Android系统提供的一种机制,用于在消息队列空闲时执行任务,其任务优先级低于主线程,适用于实时性要求不高的任务。通常用于优化Android应用启动速度。然而,matrix卡顿优化中对IdleHandler进行监控的原因在于,IdleHandler属于主线程卡顿监控的关键环节。当IdleHandler中出现耗时任务执行,会明显导致主线程卡顿。
为了进行性能优化,matrix对IdleHandler进行监控变得必要。IdleHandler监控的关键在于在TracePlugin中进行初始化和调用。构造方法仅接收配置,包含IdleHandler监控开关。onStartTrace方法调用onAlive方法,初始化HandlerThread,创建IdleHandlerLagRunnable,并启动检测IdleHandler的执行。
IdleHandlerLagRunnable负责上报信息。detectIdleHandler方法通过反射获取mIdleHandlers列表,并通过MyArrayList实现hook点,监控IdleHandler的添加和移除。当消息队列添加IdleHandler时,MyArrayList的add方法将IdleHandler包装为MyIdleHandler存入,拦截queueIdle方法调用。
MyIdleHandler继承自IdleHandler,重写queueIdle方法,监控IdleHandler执行过程。当IdleHandler执行时,idleHandlerLagHandler发送延时消息到子线程。若2s内未完成,收集信息上报,发现IdleHandler导致的卡顿问题。
IdleHandlerLagTracer通过hook替换消息队列的IdleHandlers集合,拦截添加和移除逻辑,为原IdleHandler添加代理,监控queueIdle方法执行。超时未执行完成则收集信息上报,有效发现IdleHandler导致的卡顿。
性能优化是Android开发中重要的一环,掌握IdleHandler监控机制有助于更细致地进行性能调优。此外,推荐关注Android学习资源,涵盖性能优化、框架底层原理、车载开发、逆向安全、音视频技术、Jetpack全家桶、OkHttp源码解析、Kotlin、Gradle、Flutter等多领域内容,助力深入学习和提升技术能力。
Android性能优化、框架底层原理、车载开发、逆向安全、音视频技术、Jetpack全家桶、OkHttp源码解析、Kotlin、Gradle、Flutter等学习资源,助力深化技术理解与应用。
利用Cython加速计算密集型python任务
计算密集型任务的特点是需要进行大量计算,主要消耗CPU资源,如计算圆周率、高清视频解码等。此类任务使用多任务可以完成,但任务越多,任务切换时间增加,CPU效率降低,理想情况应使任务数等于CPU核心数。Python脚本语言效率较低,不适于执行计算密集型任务。相比之下,C语言是编译型语言,通过编译器一次性将源代码转换成机器码,执行时无需再次编译,因此运行效率更高,程序可脱离语言环境独立运行。
尽管Cython可以将Python+C混合编码转换为C代码,以优化Python脚本性能或调用C函数库,但这仍然无法与C语言相比。Python语言简洁、易读、可扩展,广泛应用于Web开发、科学计算、统计、人工智能等领域。然而,对于计算密集型任务,Python性能不足。如何在选择Python的情况下提高其运行效率?多进程方法较为常见,Cython便是提升效率的一种手段。
Cython是一种让Python脚本支持C语言扩展的编译器。它能够将Python+C混合编码的.pyx脚本转换为C代码,用于优化Python脚本性能或调用C函数库。Cython是提高Python性能的常用方法之一。
以计算万以内的素数列表为例,使用Cython优化代码。首先,使用纯Python实现,然后尝试直接使用Cython将其编译为C代码。结果表明,程序执行速度有轻微提升。进一步深入代码,利用Cython分析生成的代码以识别可以优化的部分。通过指定Python数据类型,如将参数n和循环变量i、j定义为int类型,可以减少调用Python虚拟机的次数,从而显著提高程序效率。最终,经过微小的改动,程序运行速度提高了.%,比纯Python版本快了约倍。
程序的优化还可以进一步探索,如使用numpy.array替代原生列表。Python性能提升工具还包括Shed Skin、Numba、Pythran、PyPy等,它们可以从不同角度提高Python程序的运行效率。然而,选择合适的工具和优化策略,针对具体业务制定高效方案才是关键。
总结来看,尽管Python语言在某些领域具有独特优势,但在计算密集型任务中性能不足。Cython等工具可以帮助提升Python程序的运行效率,但实际性能仍可能无法与C语言相比。在选择使用Python时,结合特定的优化策略和技术工具,可以有效提高程序性能。
特别说明的是,Python的动态类型特性导致运行时效率相对较低。Cython通过指定数据类型可以减少Python虚拟机的调用,显著提升程序性能。在优化代码时,应关注循环体内的计算,尽可能减少调用Python虚拟机的次数,从而提高效率。
尽管Cython等工具能够优化Python程序的运行效率,但关键在于根据具体业务需求制定高效解决方案。《Python高性能编程》等书籍可以为Python性能优化提供更深入的了解和指导。
2024-11-29 23:23
2024-11-29 22:53
2024-11-29 22:17
2024-11-29 21:18
2024-11-29 21:02
2024-11-29 20:53