1. 修改了Serein.Library中的ObjectPool工具类,提供了对象归还的默认处理方法(通过构造方法指定Action<T>委托)

2. 不再显式调用流程上下文的Reset()方法,而改为通过对象池调用
3. 同样的,对于同样使用了ObjectPool管理上下文的Serein.Proto.WebSocket项目而言,也进行了同2.一样的修改
This commit is contained in:
fengjiayi
2025-08-23 16:19:30 +08:00
parent 5656619a3b
commit 819320f355
8 changed files with 47 additions and 49 deletions

View File

@@ -41,6 +41,9 @@ namespace Serein.Library
FlowContextPool = new Utils.ObjectPool<IFlowContext>(() => FlowContextPool = new Utils.ObjectPool<IFlowContext>(() =>
{ {
return new FlowContext(flowEnvironment); return new FlowContext(flowEnvironment);
}, context =>
{
context.Reset();
}); });
} }

View File

@@ -9,16 +9,17 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils namespace Serein.Library.Utils
{ {
/// <summary> /// <summary>
/// 具有预定义池大小限制的对象池模式的通用实现。其主要目的是将有限数量的经常使用的对象保留在池中,以便进一步回收。 ///
/// /// <para>具有预定义池大小限制的对象池模式的通用实现。其主要目的是将有限数量的经常使用的对象保留在池中,以便进一步回收。 </para>
/// 注: /// <para> </para>
/// 1)目标不是保留所有返回的对象。池不是用来存储的。如果池中没有空间,则会丢弃额外返回的对象。 /// <para>注: </para>
/// /// <para>1)目标不是保留所有返回的对象。池不是用来存储的。如果池中没有空间,则会丢弃额外返回的对象。 </para>
/// 2)这意味着如果对象是从池中获得的,调用者将在相对较短的时间内返回它 /// <para> </para>
/// 时间。长时间保持检出对象是可以的,但是会降低池的有用性。你只需要重新开始。 /// <para>2)这意味着如果对象是从池中获得的,调用者将在相对较短的时间内返回它 </para>
/// /// <para>时间。长时间保持检出对象是可以的,但是会降低池的有用性。你只需要重新开始。 </para>
/// 不将对象返回给池并不会损害池的工作,但这是一种不好的做法。 /// <para> </para>
/// 基本原理如果没有重用对象的意图就不要使用pool——只使用“new” /// <para>不将对象返回给池并不会损害池的工作,但这是一种不好的做法。 </para>
/// <para>基本原理如果没有重用对象的意图就不要使用pool——只使用“new” </para>
/// </summary> /// </summary>
public class ObjectPool<T> where T : class public class ObjectPool<T> where T : class
{ {
@@ -28,12 +29,7 @@ namespace Serein.Library.Utils
internal T Value; internal T Value;
} }
/// <summary>
/// 不使用System。Func{T},因为. net 2.0没有该类型。
/// </summary>
/// <returns></returns>
public delegate T Factory();
/// <summary> /// <summary>
/// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。 /// 池对象的存储。第一个项存储在专用字段中,因为我们希望能够满足来自它的大多数请求。
/// </summary> /// </summary>
@@ -45,14 +41,18 @@ namespace Serein.Library.Utils
/// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它。 /// 工厂在池的生命周期内被存储。只有当池需要扩展时,我们才调用它。
/// 与“new T”相比Func为实现者提供了更多的灵活性并且比“new T”更快。 /// 与“new T”相比Func为实现者提供了更多的灵活性并且比“new T”更快。
/// </summary> /// </summary>
private readonly Factory _factory; private readonly Func<T> _factory;
/// <summary>
/// 指定了 T 对象释放时的行为。
/// </summary>
private readonly Action<T>? _free;
/// <summary> /// <summary>
/// 创建一个新的对象池实例,使用指定的工厂函数和默认大小(处理器核心数的两倍)。 /// 创建一个新的对象池实例,使用指定的工厂函数和默认大小(处理器核心数的两倍)。
/// </summary> /// </summary>
/// <param name="factory"></param> /// <param name="factory"></param>
public ObjectPool(Factory factory) public ObjectPool(Func<T> factory, Action<T>? free = null) : this(factory, Environment.ProcessorCount * 2, free)
: this(factory, Environment.ProcessorCount * 2)
{ {
} }
@@ -61,10 +61,11 @@ namespace Serein.Library.Utils
/// </summary> /// </summary>
/// <param name="factory"></param> /// <param name="factory"></param>
/// <param name="size"></param> /// <param name="size"></param>
public ObjectPool(Factory factory, int size) public ObjectPool(Func<T> factory, int size, Action<T>? free = null)
{ {
Debug.Assert(size >= 1); Debug.Assert(size >= 1);
_factory = factory; _factory = factory;
_free = free;
_items = new Element[size - 1]; _items = new Element[size - 1];
} }
@@ -136,7 +137,7 @@ namespace Serein.Library.Utils
public void Free(T obj) public void Free(T obj)
{ {
Validate(obj); Validate(obj);
_free?.Invoke(obj);
if (_firstItem == null) if (_firstItem == null)
{ {
// 这里故意不使用联锁。在最坏的情况下,两个对象可能存储在同一个槽中。这是不太可能发生的,只意味着其中一个对象将被收集。 // 这里故意不使用联锁。在最坏的情况下,两个对象可能存储在同一个槽中。这是不太可能发生的,只意味着其中一个对象将被收集。

View File

@@ -40,14 +40,14 @@ namespace Serein.NodeFlow.Env
this.flowModelService = flowModelService; this.flowModelService = flowModelService;
this.UIContextOperation = UIContextOperation; this.UIContextOperation = UIContextOperation;
contexts = new ObjectPool<IFlowContext>(() => new FlowContext(flowEnvironment)); contexts = new ObjectPool<IFlowContext>(() => new FlowContext(flowEnvironment), context => context.Reset());
flowTaskOptions = new FlowWorkOptions flowTaskOptions = new FlowWorkOptions
{ {
FlowIOC = IOC, FlowIOC = IOC,
Environment = flowEnvironment, // 流程 Environment = flowEnvironment, // 流程
FlowContextPool = contexts, // 上下文对象池 FlowContextPool = contexts, // 上下文对象池
}; };
flowTaskManagementPool = new ObjectPool<FlowWorkManagement>(()=> new FlowWorkManagement(flowTaskOptions)); flowTaskManagementPool = new ObjectPool<FlowWorkManagement>(()=> new FlowWorkManagement(flowTaskOptions), fwm => fwm.Exit());
} }
private ObjectPool<IFlowContext> contexts; private ObjectPool<IFlowContext> contexts;
@@ -102,7 +102,6 @@ namespace Serein.NodeFlow.Env
{ {
flowWorkManagements.Remove(fwm); flowWorkManagements.Remove(fwm);
} }
fwm.Exit();
flowTaskManagementPool.Free(fwm); flowTaskManagementPool.Free(fwm);
} }
@@ -257,7 +256,6 @@ namespace Serein.NodeFlow.Env
} }
}); });
} }
context.Reset();
flowContextPool.Free(context); flowContextPool.Free(context);
ReturnFWM(flowWorkManagement); // 释放流程任务管理器 ReturnFWM(flowWorkManagement); // 释放流程任务管理器
if (flowResult.Value is TResult result) if (flowResult.Value is TResult result)
@@ -330,7 +328,6 @@ namespace Serein.NodeFlow.Env
} }
}); });
} }
context.Reset();
flowContextPool.Free(context); flowContextPool.Free(context);
ReturnFWM(flowWorkManagement); // 释放流程任务管理器 ReturnFWM(flowWorkManagement); // 释放流程任务管理器
} }

View File

@@ -184,7 +184,6 @@ namespace Serein.NodeFlow.Model.Infos
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
sb.AppendCode(3, $"finally"); sb.AppendCode(3, $"finally");
sb.AppendCode(3, $"{{"); sb.AppendCode(3, $"{{");
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
@@ -272,7 +271,6 @@ namespace Serein.NodeFlow.Model.Infos
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
sb.AppendCode(3, $"finally"); sb.AppendCode(3, $"finally");
sb.AppendCode(3, $"{{"); sb.AppendCode(3, $"{{");
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
@@ -297,7 +295,6 @@ namespace Serein.NodeFlow.Model.Infos
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
sb.AppendCode(3, $"finally"); sb.AppendCode(3, $"finally");
sb.AppendCode(3, $"{{"); sb.AppendCode(3, $"{{");
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
sb.AppendCode(3, $"}}"); sb.AppendCode(3, $"}}");
sb.AppendCode(2, $"}}"); sb.AppendCode(2, $"}}");

View File

@@ -197,7 +197,6 @@ namespace Serein.NodeFlow.Services
var context = pool.Allocate(); var context = pool.Allocate();
var instance = ioc.Get(md.ActingInstanceType); var instance = ioc.Get(md.ActingInstanceType);
await dd.InvokeAsync(instance, [context]); await dd.InvokeAsync(instance, [context]);
context.Reset();
pool.Free(context); pool.Free(context);
} }
ioc.Build(); // 绑定初始化时注册的类型 ioc.Build(); // 绑定初始化时注册的类型
@@ -225,7 +224,6 @@ namespace Serein.NodeFlow.Services
var context = pool.Allocate(); var context = pool.Allocate();
var instance = ioc.Get(md.ActingInstanceType); var instance = ioc.Get(md.ActingInstanceType);
await dd.InvokeAsync(instance, [context]); await dd.InvokeAsync(instance, [context]);
context.Reset();
pool.Free(context); pool.Free(context);
} }
ioc.Build(); // 绑定初始化时注册的类型 ioc.Build(); // 绑定初始化时注册的类型
@@ -255,7 +253,6 @@ namespace Serein.NodeFlow.Services
var context = pool.Allocate(); var context = pool.Allocate();
var instance = ioc.Get(md.ActingInstanceType); var instance = ioc.Get(md.ActingInstanceType);
await dd.InvokeAsync(instance, [context]); await dd.InvokeAsync(instance, [context]);
context.Reset();
pool.Free(context); pool.Free(context);
} }
@@ -304,7 +301,6 @@ namespace Serein.NodeFlow.Services
var token = WorkOptions.CancellationTokenSource.Token; var token = WorkOptions.CancellationTokenSource.Token;
var context = pool.Allocate(); var context = pool.Allocate();
await startNode.StartFlowAsync(context, token); await startNode.StartFlowAsync(context, token);
context.Reset();
pool.Free(context); pool.Free(context);
return; return;
} }
@@ -330,7 +326,6 @@ namespace Serein.NodeFlow.Services
var result = await startNode.StartFlowAsync(context, WorkOptions.CancellationTokenSource.Token); // 开始运行时从选定节点开始运行 var result = await startNode.StartFlowAsync(context, WorkOptions.CancellationTokenSource.Token); // 开始运行时从选定节点开始运行
checkpoints["执行流程"] = sw.Elapsed; checkpoints["执行流程"] = sw.Elapsed;
context.Reset();
pool.Free(context); pool.Free(context);
checkpoints["释放Context"] = sw.Elapsed; checkpoints["释放Context"] = sw.Elapsed;
@@ -437,8 +432,6 @@ namespace Serein.NodeFlow.Services
} }
finally finally
{ {
context.Reset();
pool.Free(context); pool.Free(context);
} }
} }

View File

@@ -344,7 +344,7 @@ namespace Serein.Proto.WebSocket.Handle
return; return;
} }
// 返回结果 // 返回结果
var responseData = context.OnReplyMakeData(context, data); var responseData = context.OnReplyMakeData?.Invoke(context, data);
if (responseData is null) if (responseData is null)
{ {
context.TriggerExceptionTracking(new ArgumentNullException($"处理回调函数 OnReplyMakeData 返回 null")); context.TriggerExceptionTracking(new ArgumentNullException($"处理回调函数 OnReplyMakeData 返回 null"));

View File

@@ -325,14 +325,22 @@ namespace Serein.Proto.WebSocket
{ {
await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入 await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
} }
/*
ObjectPool<WebSocketMsgContext> contextPool = new ObjectPool<WebSocketMsgContext>(() => ObjectPool<WebSocketHandleContext> contextPool = new ObjectPool<WebSocketHandleContext>(() =>
{ {
return new WebSocketMsgContext(sendasync); var context = new WebSocketHandleContext(sendasync);
}, 20); context.OnExceptionTracking = _onExceptionTracking;
var context = contextPool.Allocate(); context.OnReplyMakeData = _onReplyMakeData;
contextPool.Free(context); context.OnReply = _onReply;
*/ return context;
}, context =>
{
context.MsgRequest = null;
context.MsgData = null;
context.ErrorMessage = null;
context.Model = null;
});
while (webSocket.State == WebSocketState.Open) while (webSocket.State == WebSocketState.Open)
{ {
var message = await tranTool.WaitMsgAsync(); // 有消息时通知 var message = await tranTool.WaitMsgAsync(); // 有消息时通知
@@ -341,12 +349,10 @@ namespace Serein.Proto.WebSocket
Console.WriteLine($"WebSocket 消息解析失败: {message}"); Console.WriteLine($"WebSocket 消息解析失败: {message}");
continue; continue;
} }
var context = new WebSocketHandleContext(sendasync); var context = contextPool.Allocate();
context.MsgRequest = jsonReques; context.MsgRequest = jsonReques;
context.OnExceptionTracking = _onExceptionTracking;
context.OnReplyMakeData = _onReplyMakeData;
context.OnReply = _onReply;
await HandleAsync(context); // 处理消息 await HandleAsync(context); // 处理消息
contextPool.Free(context);
} }
} }

View File

@@ -69,6 +69,7 @@
<ProjectReference Include="..\Library\Serein.Library.csproj" /> <ProjectReference Include="..\Library\Serein.Library.csproj" />
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" /> <ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />
<ProjectReference Include="..\Serein.Extend.NewtonsoftJson\Serein.Extend.NewtonsoftJson.csproj" /> <ProjectReference Include="..\Serein.Extend.NewtonsoftJson\Serein.Extend.NewtonsoftJson.csproj" />
<ProjectReference Include="..\Serein.Proto.Modbus\Serein.Proto.Modbus.csproj" />
<ProjectReference Include="..\Serein.Script\Serein.Script.csproj" /> <ProjectReference Include="..\Serein.Script\Serein.Script.csproj" />
</ItemGroup> </ItemGroup>