Skip to content

Commit 5496751

Browse files
committed
perf:优化异步终结点性能
1 parent 5cb74d0 commit 5496751

3 files changed

Lines changed: 73 additions & 13 deletions

File tree

Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WatchAssemblyContext.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
using System;
1+
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Reflection;
5+
using System.Threading.Tasks;
56

67
namespace Cyaim.WebSocketServer.Infrastructure.Configures
78
{
@@ -52,5 +53,11 @@ public class WatchAssemblyContext
5253
/// K MethodInfo,V ParameterInfo
5354
/// </summary>
5455
public Dictionary<MethodInfo, ParameterInfo[]> MethodParameters { get; set; }
56+
57+
/// <summary>
58+
/// Task result getter cache in endpoint method
59+
/// K endpoint MethodInfo,V Task result getter
60+
/// </summary>
61+
public Dictionary<MethodInfo, Func<Task, object>> MethodTaskResultGetters { get; set; }
5562
}
5663
}

Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Cyaim.WebSocketServer.Infrastructure.AccessControl;
1+
using Cyaim.WebSocketServer.Infrastructure.AccessControl;
22
using Cyaim.WebSocketServer.Infrastructure.Configures;
33
using Cyaim.WebSocketServer.Infrastructure.Injectors;
44
using Cyaim.WebSocketServer.Infrastructure.Metrics;
@@ -976,24 +976,26 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
976976
invokeResult = methodInvoker.Invoke(inst, args);
977977

978978
// Async api support
979-
if (invokeResult is Task)
979+
if (invokeResult is Task task)
980980
{
981-
dynamic invokeResultTask = invokeResult;
982-
//await invokeResultTask;
983-
await Task.WhenAny(invokeResultTask, Task.Delay(Timeout.Infinite, appLifetime.ApplicationStopping));
981+
await Task.WhenAny(task, Task.Delay(Timeout.Infinite, appLifetime.ApplicationStopping));
984982

985-
if (invokeResultTask.Exception != null)
983+
if (task.Exception != null)
986984
{
987-
throw invokeResultTask.Exception;
985+
throw task.Exception;
988986
}
989987

990-
try
988+
if (method.ReturnType == typeof(Task))
991989
{
992-
invokeResult = invokeResultTask.Result;
990+
invokeResult = null;
993991
}
994-
catch (RuntimeBinderException)
992+
else
995993
{
996-
invokeResult = null;
994+
Func<Task, object> taskResultGetter = null;
995+
webSocketOptions.WatchAssemblyContext.MethodTaskResultGetters?.TryGetValue(method, out taskResultGetter);
996+
invokeResult = taskResultGetter != null
997+
? taskResultGetter(task)
998+
: null;
997999
}
9981000
}
9991001

Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketRouteServiceCollectionExtensions.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Cyaim.WebSocketServer.Infrastructure.Attributes;
1+
using Cyaim.WebSocketServer.Infrastructure.Attributes;
22
using Cyaim.WebSocketServer.Infrastructure.Configures;
33
using Microsoft.Extensions.Configuration;
44
using Microsoft.Extensions.DependencyInjection;
@@ -10,7 +10,9 @@
1010
using System.Collections.Generic;
1111
using System.Globalization;
1212
using System.Linq;
13+
using System.Linq.Expressions;
1314
using System.Reflection;
15+
using System.Threading.Tasks;
1416

1517
namespace Cyaim.WebSocketServer.Infrastructure
1618
{
@@ -182,6 +184,20 @@ public static void ConfigureWebSocketRoute(this IServiceCollection services, ICo
182184

183185
#endregion
184186

187+
#region 计算终结点返回值Task<TResult>结果读取器缓存
188+
189+
var methodTaskResultGetters = new Dictionary<MethodInfo, Func<Task, object>>();
190+
foreach (var item in points.Select(x => x.MethodInfo))
191+
{
192+
if (TryBuildTaskResultGetter(item.ReturnType, out var taskResultGetter))
193+
{
194+
methodTaskResultGetters[item] = taskResultGetter;
195+
}
196+
}
197+
wsrOptions.WatchAssemblyContext.MethodTaskResultGetters = methodTaskResultGetters;
198+
199+
#endregion
200+
185201
services.AddSingleton(x => wsrOptions);
186202

187203
//services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
@@ -194,6 +210,41 @@ public static void ConfigureWebSocketRoute(this IServiceCollection services, ICo
194210
var defaultCultureInfo = CultureInfo.CurrentCulture;
195211
}
196212

213+
/// <summary>
214+
/// 编译表达式树以获取 Task<TResult> 的结果,避免每次通过反射访问 Result 属性的性能开销。
215+
/// </summary>
216+
/// <param name="returnType"></param>
217+
/// <param name="getter"></param>
218+
/// <returns></returns>
219+
private static bool TryBuildTaskResultGetter(Type returnType, out Func<Task, object> getter)
220+
{
221+
getter = null;
222+
if (returnType == null || !returnType.IsGenericType)
223+
{
224+
return false;
225+
}
226+
227+
var genericTypeDef = returnType.GetGenericTypeDefinition();
228+
if (genericTypeDef != typeof(Task<>))
229+
{
230+
return false;
231+
}
232+
233+
var resultType = returnType.GenericTypeArguments[0];
234+
if (resultType.Name == "VoidTaskResult" && resultType.Namespace == "System.Threading.Tasks")
235+
{
236+
return false;
237+
}
238+
239+
var taskParam = Expression.Parameter(typeof(Task), "task");
240+
var castTask = Expression.Convert(taskParam, returnType);
241+
var resultProperty = Expression.Property(castTask, "Result");
242+
var castResult = Expression.Convert(resultProperty, typeof(object));
243+
244+
getter = Expression.Lambda<Func<Task, object>>(castResult, taskParam).Compile();
245+
return true;
246+
}
247+
197248
/// <summary>
198249
/// Get assembly controller "WebSocket" EndPoint
199250
/// </summary>

0 commit comments

Comments
 (0)