From 3e604ee2fdb614d54b977067694c44a45255b577 Mon Sep 17 00:00:00 2001 From: "2248356998 qq.com" <2248356998@qq.com> Date: Sun, 19 Oct 2025 19:39:42 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=8F=98=E9=87=8F=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=88=9B=E5=BB=BA=E6=9C=BA=E6=9E=84=E7=AD=89=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E6=94=B9=E7=94=A8=E7=BB=91=E5=AE=9A=E7=9A=84?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=9A=84=E6=9C=BA=E6=9E=84=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reflection/Reflect.cs | 12 + .../Threading/TimerScheduler.cs | 7 + src/Directory.Build.props | 6 +- .../Controller/ControlController.cs | 12 +- .../Entity/Variable.cs | 2 +- .../GlobalData/GlobalData.cs | 62 ++- .../Mapper/GatewayMapper.cs | 2 + .../Model/VariableRunTime.cs | 6 - .../Services/Variable/VariableService.cs | 58 +-- .../Benchmark/BenchmarkAsyncWaitData.cs | 426 ------------------ .../Benchmark/TimeoutBenchmark.cs | 3 +- 11 files changed, 116 insertions(+), 480 deletions(-) delete mode 100644 src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/BenchmarkAsyncWaitData.cs diff --git a/src/Admin/ThingsGateway.NewLife.X/Reflection/Reflect.cs b/src/Admin/ThingsGateway.NewLife.X/Reflection/Reflect.cs index f7b290317..f919cdcfb 100644 --- a/src/Admin/ThingsGateway.NewLife.X/Reflection/Reflect.cs +++ b/src/Admin/ThingsGateway.NewLife.X/Reflection/Reflect.cs @@ -580,7 +580,19 @@ public static class Reflect return func; } + /// 把一个方法转为泛型委托,便于快速反射调用 + /// + /// + /// + /// + public static void RemoveCache(this MethodInfo method, object? target = null) where TFunc : class + { + if (method == null) return; + var key = new DelegateCacheKey(method, typeof(TFunc), target); + + DelegateCache.Cache.TryRemove(key); + } #endregion } public static class DelegateCache diff --git a/src/Admin/ThingsGateway.NewLife.X/Threading/TimerScheduler.cs b/src/Admin/ThingsGateway.NewLife.X/Threading/TimerScheduler.cs index 65778c688..35c5b043f 100644 --- a/src/Admin/ThingsGateway.NewLife.X/Threading/TimerScheduler.cs +++ b/src/Admin/ThingsGateway.NewLife.X/Threading/TimerScheduler.cs @@ -191,6 +191,13 @@ public class TimerScheduler : IDisposable, ILogFeature Count--; } } + + timer.Method.RemoveCache(timer.Target.Target); +#if NET6_0_OR_GREATER + timer.Method.RemoveCache>(timer.Target.Target); +#endif + timer.Method.RemoveCache>(timer.Target.Target); + } private AutoResetEvent? _waitForTimer; diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 4dd9fd735..e0f66db04 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,9 +1,9 @@ - 10.11.114 - 10.11.114 - 10.11.114 + 10.11.115 + 10.11.115 + 10.11.115 10.11.6 10.11.6 8.0.21 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Controller/ControlController.cs b/src/Gateway/ThingsGateway.Gateway.Application/Controller/ControlController.cs index ebd710151..b926fc513 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Controller/ControlController.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Controller/ControlController.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.ComponentModel; +using ThingsGateway.NewLife.DictionaryExtensions; using ThingsGateway.FriendlyException; @@ -122,16 +123,11 @@ public class ControlController : ControllerBase, IRpcServer [TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)] public async Task>> WriteVariablesAsync([FromBody][TouchSocket.WebApi.FromBody] Dictionary> deviceDatas) { - foreach (var deviceData in deviceDatas) - { - if (GlobalData.Devices.TryGetValue(deviceData.Key, out var device)) - { - var data = device.VariableRuntimes.Where(a => deviceData.Value.ContainsKey(a.Key)).ToList(); - await GlobalData.SysUserService.CheckApiDataScopeAsync(data.Select(a => a.Value.CreateOrgId), data.Select(a => a.Value.CreateUserId)).ConfigureAwait(false); - } - } + await GlobalData.CheckByDeviceNames(deviceDatas.Select(a => a.Key)).ConfigureAwait(false); return (await GlobalData.RpcService.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext?.GetRemoteIpAddressToIPv4()}", deviceDatas).ConfigureAwait(false)).ToDictionary(a => a.Key, a => a.Value.ToDictionary(b => b.Key, b => (OperResult)b.Value)); + + } /// diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs index a5bf7fd1a..661dc68e2 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs @@ -28,7 +28,7 @@ namespace ThingsGateway.Gateway.Application; [SugarIndex("index_device", nameof(Variable.DeviceId), OrderByType.Asc)] [SugarIndex("unique_deviceid_variable_name", nameof(Variable.Name), OrderByType.Asc, nameof(Variable.DeviceId), OrderByType.Asc, true)] #endif -public class Variable : BaseDataEntity, IValidatableObject +public class Variable : PrimaryKeyEntity, IValidatableObject { /// /// 主键Id diff --git a/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs b/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs index f504af2b8..65e02f7a5 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs @@ -15,6 +15,7 @@ using PooledAwait; using System.Collections.Concurrent; using ThingsGateway.Extension.Generic; +using ThingsGateway.NewLife.DictionaryExtensions; namespace ThingsGateway.Gateway.Application; @@ -109,11 +110,15 @@ public static class GlobalData static async PooledTask> GetCurrentUserDevices() { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); - return ReadOnlyIdDevices.WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 + return IdDevices.WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 .WhereIf(dataScope?.Count == 0, u => u.Value.CreateUserId == UserManager.UserId).Select(a => a.Value); } } - + public static IEnumerable GetCurrentUserDeviceIds(HashSet dataScope) + { + return IdDevices.WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 + .WhereIf(dataScope?.Count == 0, u => u.Value.CreateUserId == UserManager.UserId).Select(a => a.Key); + } public static Task> GetCurrentUserIdVariables() { return GetCurrentUserIdVariables(); @@ -121,11 +126,53 @@ public static class GlobalData static async PooledTask> GetCurrentUserIdVariables() { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); - return IdVariables.Where(a => a.Value.IsInternalMemoryVariable == false).WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 - .WhereIf(dataScope?.Count == 0, u => u.Value.CreateUserId == UserManager.UserId).Select(a => a.Value); + + return IdVariables.Where(a => a.Value.IsInternalMemoryVariable == false) + .WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.DeviceRuntime.CreateOrgId))//在指定机构列表查询 + .WhereIf(dataScope?.Count == 0, u => u.Value.DeviceRuntime.CreateUserId == UserManager.UserId).Select(a => a.Value); } } + public static async Task CheckByDeviceNames(IEnumerable deviceNames) + { + List orgids = new(); + List userIds = new(); + foreach (var deviceData in GlobalData.Devices.FilterByKeys(deviceNames)) + { + orgids.Add(deviceData.Value.CreateOrgId); + userIds.Add(deviceData.Value.CreateUserId); + } + await GlobalData.SysUserService.CheckApiDataScopeAsync(orgids, userIds).ConfigureAwait(false); + } + public static async Task CheckByDeviceIds(IEnumerable deviceIds) + { + List orgids = new(); + List userIds = new(); + foreach (var deviceData in GlobalData.IdDevices.FilterByKeys(deviceIds)) + { + orgids.Add(deviceData.Value.CreateOrgId); + userIds.Add(deviceData.Value.CreateUserId); + } + await GlobalData.SysUserService.CheckApiDataScopeAsync(orgids, userIds).ConfigureAwait(false); + } + public static async Task CheckByVariableIds(IEnumerable variableIds) + { + List orgids = new(); + List userIds = new(); + foreach (var deviceData in GlobalData.IdVariables.FilterByKeys(variableIds)) + { + orgids.Add(deviceData.Value.DeviceRuntime.CreateOrgId); + userIds.Add(deviceData.Value.DeviceRuntime.CreateUserId); + } + await GlobalData.SysUserService.CheckApiDataScopeAsync(orgids, userIds).ConfigureAwait(false); + } + public static async Task CheckByVariableId(long variableId) + { + if (GlobalData.IdVariables.TryGetValue(variableId, out var variable)) + { + await GlobalData.SysUserService.CheckApiDataScopeAsync(variable.DeviceRuntime.CreateOrgId, variable.DeviceRuntime.CreateUserId).ConfigureAwait(false); + } + } public static Task> GetCurrentUserRealAlarmVariablesAsync() { return GetCurrentUserRealAlarmVariablesAsync(); @@ -133,7 +180,8 @@ public static class GlobalData static async PooledTask> GetCurrentUserRealAlarmVariablesAsync() { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); - return RealAlarmIdVariables.WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 + return RealAlarmIdVariables + .WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 .WhereIf(dataScope?.Count == 0, u => u.Value.CreateUserId == UserManager.UserId).Select(a => a.Value); } } @@ -145,8 +193,8 @@ public static class GlobalData static async PooledTask> GetCurrentUserAlarmEnableVariables() { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); - return AlarmEnableIdVariables.Where(a => a.Value.IsInternalMemoryVariable == false).WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.CreateOrgId))//在指定机构列表查询 - .WhereIf(dataScope?.Count == 0, u => u.Value.CreateUserId == UserManager.UserId).Select(a => a.Value); + return AlarmEnableIdVariables.Where(a => a.Value.IsInternalMemoryVariable == false).WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.Value.DeviceRuntime.CreateOrgId))//在指定机构列表查询 + .WhereIf(dataScope?.Count == 0, u => u.Value.DeviceRuntime.CreateUserId == UserManager.UserId).Select(a => a.Value); } } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs b/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs index d952a42ce..7475a4af9 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs @@ -26,6 +26,8 @@ public static partial class GatewayMapper [MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.EventTime)}", nameof(AlarmVariable.EventTime))] [MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmType)}", nameof(AlarmVariable.AlarmType))] [MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.EventType)}", nameof(AlarmVariable.EventType))] + [MapProperty($"{nameof(VariableRuntime.DeviceRuntime)}.{nameof(DeviceRuntime.CreateOrgId)}", nameof(AlarmVariable.CreateOrgId))] + [MapProperty($"{nameof(VariableRuntime.DeviceRuntime)}.{nameof(DeviceRuntime.CreateUserId)}", nameof(AlarmVariable.CreateUserId))] public static partial AlarmVariable AdaptAlarmVariable(this VariableRuntime src); public static partial VariableDataWithValue AdaptVariableDataWithValue(this VariableBasicData src); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs b/src/Gateway/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs index a23635f10..5e536143c 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs @@ -66,11 +66,6 @@ public partial class VariableRuntime : Variable [AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true, Order = 5)] public DateTime CollectTime { get => collectTime; set => collectTime = value; } - [SugarColumn(ColumnDescription = "排序码", IsNullable = true)] - [AutoGenerateColumn(Visible = false, DefaultSort = false, Sortable = true)] - [IgnoreExcel] - public override int SortCode { get => sortCode; set => sortCode = value; } - /// /// 上次值 /// @@ -245,7 +240,6 @@ public partial class VariableRuntime : Variable private int index; - private int sortCode; private DateTime changeTime = DateTime.UnixEpoch.ToLocalTime(); private DateTime collectTime = DateTime.UnixEpoch.ToLocalTime(); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs index 0123757c6..a7baef68b 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs @@ -22,7 +22,6 @@ using System.Text; using ThingsGateway.Common.Extension; using ThingsGateway.Common.Extension.Generic; -using ThingsGateway.Extension.Generic; using ThingsGateway.Foundation.Extension.Dynamic; using TouchSocket.Core; @@ -107,8 +106,6 @@ internal sealed class VariableService : BaseService, IVariableService variable.DataType = DataTypeEnum.Int16; variable.Name = name; variable.Id = id; - variable.CreateOrgId = UserManager.OrgId; - variable.CreateUserId = UserManager.UserId; variable.DeviceId = device.Id; variable.RegisterAddress = address; newVariables.Add(variable); @@ -334,8 +331,6 @@ internal sealed class VariableService : BaseService, IVariableService variable.DataType = DataTypeEnum.Int16; variable.Name = name; variable.Id = id; - variable.CreateOrgId = UserManager.OrgId; - variable.CreateUserId = UserManager.UserId; variable.DeviceId = device.Id; variable.RegisterAddress = address; newVariables.Add(variable); @@ -428,12 +423,9 @@ internal sealed class VariableService : BaseService, IVariableService differences.Remove(nameof(Variable.VariablePropertys)); if (differences?.Count > 0) { + var data = models.ToList(); + await GlobalData.CheckByDeviceIds(data.Select(a => a.DeviceId)).ConfigureAwait(false); using var db = GetDB(); - var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); - var data = models - .WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 - .WhereIf(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) - .ToList(); var result = (await db.Updateable(data).UpdateColumns(differences.Select(a => a.Key).ToArray()).ExecuteCommandAsync().ConfigureAwait(false)) > 0; @@ -448,24 +440,20 @@ internal sealed class VariableService : BaseService, IVariableService [OperDesc("DeleteVariable", isRecordPar: false, localizerType: typeof(Variable))] public async Task DeleteByDeviceIdAsync(IEnumerable input, SqlSugarClient db) { - var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); var ids = input.ToList(); - var result = await db.Deleteable().Where(a => ids.Contains(a.DeviceId)) - .WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 - .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) - .ExecuteCommandAsync().ConfigureAwait(false); + await GlobalData.CheckByDeviceIds(ids).ConfigureAwait(false); + var result = await db.Deleteable().Where(a => ids.Contains(a.DeviceId)) + .ExecuteCommandAsync().ConfigureAwait(false); } [OperDesc("DeleteVariable", isRecordPar: false, localizerType: typeof(Variable))] public async Task DeleteVariableAsync(IEnumerable input) { using var db = GetDB(); - var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); var ids = input?.ToList(); + await GlobalData.CheckByVariableIds(ids).ConfigureAwait(false); var result = (await db.Deleteable().WhereIF(input != null, a => ids.Contains(a.Id)) - .WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 - .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) .ExecuteCommandAsync().ConfigureAwait(false)) > 0; return result; @@ -505,6 +493,11 @@ internal sealed class VariableService : BaseService, IVariableService private async Task, ISugarQueryable>> GetWhereQueryFunc(GatewayExportFilter exportFilter) { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); + List? filterDeviceIds= null; + if(dataScope!=null) + { + filterDeviceIds= GlobalData.GetCurrentUserDeviceIds(dataScope).ToList(); + } HashSet? deviceId = null; if (!exportFilter.PluginName.IsNullOrWhiteSpace()) { @@ -520,8 +513,7 @@ internal sealed class VariableService : BaseService, IVariableService .WhereIF(exportFilter.PluginType == PluginTypeEnum.Collect, a => a.DeviceId == exportFilter.DeviceId) .WhereIF(deviceId != null, a => deviceId.Contains(a.DeviceId)) - .WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 - .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) + .WhereIF(filterDeviceIds != null , u => filterDeviceIds.Contains(u.DeviceId))//在指定机构列表查询 .WhereIF(exportFilter.PluginType == PluginTypeEnum.Business, u => SqlFunc.JsonLike(u.VariablePropertys, exportFilter.DeviceId.ToString())); return whereQuery; @@ -530,6 +522,13 @@ internal sealed class VariableService : BaseService, IVariableService private async Task, IEnumerable>> GetWhereEnumerableFunc(GatewayExportFilter exportFilter, bool sql = false) { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); + List? filterDeviceIds = null; + if (dataScope != null) + { + filterDeviceIds = GlobalData.GetCurrentUserDeviceIds(dataScope).ToList(); + } + + HashSet? deviceId = null; if (!exportFilter.PluginName.IsNullOrWhiteSpace()) { @@ -545,8 +544,7 @@ internal sealed class VariableService : BaseService, IVariableService .WhereIF(exportFilter.PluginType == PluginTypeEnum.Collect, a => a.DeviceId == exportFilter.DeviceId) .WhereIF(deviceId != null, a => deviceId.Contains(a.DeviceId)) - .WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 - .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) + .WhereIF(filterDeviceIds != null, u => filterDeviceIds.Contains(u.DeviceId))//在指定机构列表查询 .WhereIF(sql && exportFilter.PluginType == PluginTypeEnum.Business, u => SqlFunc.JsonLike(u.VariablePropertys, exportFilter.DeviceId.ToString())) .WhereIF(!sql && exportFilter.PluginType == PluginTypeEnum.Business && exportFilter.DeviceId > 0, u => @@ -566,7 +564,7 @@ internal sealed class VariableService : BaseService, IVariableService public async Task SaveVariableAsync(Variable input, ItemChangedType type) { if (type == ItemChangedType.Update) - await GlobalData.SysUserService.CheckApiDataScopeAsync(input.CreateOrgId, input.CreateUserId).ConfigureAwait(false); + await GlobalData.CheckByVariableId(input.Id).ConfigureAwait(false); else ManageHelper.CheckVariableCount(1); @@ -767,6 +765,13 @@ internal sealed class VariableService : BaseService, IVariableService public ImportPreviewOutput> SetVariableData(HashSet? dataScope, IReadOnlyDictionary deviceDicts, Dictionary ImportPreviews, ImportPreviewOutput> deviceImportPreview, Dictionary driverPluginNameDict, NonBlockingDictionary, Dictionary)> propertysDict, string sheetName, IEnumerable> rows) { + + List? filterDeviceIds = null; + if (dataScope != null) + { + filterDeviceIds = GlobalData.GetCurrentUserDeviceIds(dataScope).ToList(); + } + string ImportNullError = Localizer["ImportNullError"]; string RedundantDeviceError = Localizer["RedundantDeviceError"]; @@ -839,17 +844,14 @@ internal sealed class VariableService : BaseService, IVariableService if (GlobalData.IdDevices.TryGetValue(variable.DeviceId, out var dbvar1s) && dbvar1s.VariableRuntimes.TryGetValue(variable.Name, out var dbvar1)) { variable.Id = dbvar1.Id; - variable.CreateOrgId = dbvar1.CreateOrgId; - variable.CreateUserId = dbvar1.CreateUserId; variable.IsUp = true; } else { variable.IsUp = false; - variable.CreateOrgId = UserManager.OrgId; - variable.CreateUserId = UserManager.UserId; } - if (device.IsUp && ((dataScope != null && dataScope?.Count > 0 && !dataScope.Contains(variable.CreateOrgId)) || dataScope?.Count == 0 && variable.CreateUserId != UserManager.UserId)) + + if (device.IsUp && (filterDeviceIds?.Contains(variable.DeviceId) != false)) { importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, "Operation not permitted")); } diff --git a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/BenchmarkAsyncWaitData.cs b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/BenchmarkAsyncWaitData.cs deleted file mode 100644 index 48b78c73b..000000000 --- a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/BenchmarkAsyncWaitData.cs +++ /dev/null @@ -1,426 +0,0 @@ -// ------------------------------------------------------------------------------ -// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 -// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 -// CSDN博客:https://blog.csdn.net/qq_40374647 -// 哔哩哔哩视频:https://space.bilibili.com/94253567 -// Gitee源代码仓库:https://gitee.com/RRQM_Home -// Github源代码仓库:https://github.com/RRQM -// API首页:https://touchsocket.net/ -// 交流QQ群:234762506 -// 感谢您的下载和使用 -// ------------------------------------------------------------------------------ - -using BenchmarkDotNet.Attributes; - -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Threading.Tasks.Sources; - -using TouchSocket.Core; - -namespace BenchmarkConsoleApp; - - -[MemoryDiagnoser] -public class BenchmarkAsyncWaitData -{ - private int Count = 100000; - - [Benchmark] - public async Task RunAsyncWaitDataPool() - { - var waitHandlePool = new WaitHandlePool(); - var cts = new CancellationTokenSource(1000 * 60); - for (var i = 0; i < this.Count; i++) - { - var data = new MyWaitData(); - using (var waitData = waitHandlePool.GetWaitDataAsync(data)) - { - var task = Task.Run(() => - { - waitHandlePool.Set(data); - }); - - - await waitData.WaitAsync(cts.Token).ConfigureAwait(false); - - await task; - } - } - - } - - [Benchmark] - public async Task RunAsyncWaitData() - { - var waitHandlePool = new WaitHandlePool2(); - var cts = new CancellationTokenSource(1000 * 60); - for (var i = 0; i < this.Count; i++) - { - var data = new MyWaitData(); - using (var waitData = waitHandlePool.GetWaitDataAsync(data)) - { - var task = Task.Run(() => - { - waitHandlePool.Set(data); - }); - - - await waitData.WaitAsync(cts.Token).ConfigureAwait(false); - - await task; - } - } - } - - [Benchmark] - public async Task RunAsyncWaitDataDelayPool() - { - var waitHandlePool = new WaitHandlePool(); - var cts = new CancellationTokenSource(1000 * 60); - for (var i = 0; i < this.Count; i++) - { - var data = new MyWaitData(); - using (var waitData = waitHandlePool.GetWaitDataAsync(data)) - { - var task = waitData.WaitAsync(cts.Token).ConfigureAwait(false); - - waitData.Set(data); - - await task; - } - } - - } - - [Benchmark] - public async Task RunAsyncWaitDataDelay() - { - var waitHandlePool = new WaitHandlePool2(); - var cts = new CancellationTokenSource(1000 * 60); - for (var i = 0; i < this.Count; i++) - { - var data = new MyWaitData(); - using (var waitData = waitHandlePool.GetWaitDataAsync(data)) - { - var task = waitData.WaitAsync(cts.Token).ConfigureAwait(false); - - waitData.Set(data); - - await task; - } - } - - } - - private class MyWaitData : IWaitHandle - { - public int Sign { get; set; } - } - - public sealed class WaitHandlePool2 - where T : class, IWaitHandle - { - private readonly int m_maxSign; - private readonly int m_minSign; - private readonly ConcurrentDictionary> m_waitDic = new(); - private readonly Action _remove; - private int m_currentSign; - - /// - /// 初始化类的新实例。 - /// - /// 签名的最小值,默认为1。 - /// 签名的最大值,默认为。 - /// - /// 签名范围用于控制自动生成的唯一标识符的取值范围。 - /// 当签名达到最大值时,会自动重置到最小值重新开始分配。 - /// - public WaitHandlePool2(int minSign = 1, int maxSign = int.MaxValue) - { - this.m_minSign = minSign; - this.m_currentSign = minSign; - this.m_maxSign = maxSign; - - this._remove = this.Remove; - } - - /// - /// 取消池中所有等待操作。 - /// - /// - /// 此方法会遍历池中所有的等待数据,并调用其方法来取消等待。 - /// 取消后的等待数据会从池中移除。适用于应用程序关闭或需要批量取消所有等待操作的场景。 - /// - public void CancelAll() - { - var signs = this.m_waitDic.Keys.ToList(); - foreach (var sign in signs) - { - if (this.m_waitDic.TryRemove(sign, out var item)) - { - item.Cancel(); - } - } - } - - /// - /// 获取与指定结果关联的异步等待数据。 - /// - /// 要关联的结果对象。 - /// 指示是否自动为结果对象分配签名,默认为。 - /// 创建的实例。 - /// 当指定的签名已被使用时抛出。 - /// - /// 如果,方法会自动为结果对象生成唯一签名。 - /// 创建的等待数据会被添加到池中,直到被设置结果或取消时才会移除。 - /// - public AsyncWaitData2 GetWaitDataAsync(T result, bool autoSign = true) - { - if (autoSign) - { - result.Sign = this.GetSign(); - } - var waitDataAsyncSlim = new AsyncWaitData2(result.Sign, this._remove, result); - - if (!this.m_waitDic.TryAdd(result.Sign, waitDataAsyncSlim)) - { - //ThrowHelper.ThrowInvalidOperationException($"The sign '{result.Sign}' is already in use."); - return default; - } - return waitDataAsyncSlim; - } - - /// - /// 获取具有自动生成签名的异步等待数据。 - /// - /// 输出参数,返回自动生成的签名值。 - /// 创建的实例。 - /// 当生成的签名已被使用时抛出。 - /// - /// 此方法会自动生成唯一签名,并创建不包含挂起数据的等待对象。 - /// 适用于只需要等待通知而不关心具体数据内容的场景。 - /// - public AsyncWaitData2 GetWaitDataAsync(out int sign) - { - sign = this.GetSign(); - var waitDataAsyncSlim = new AsyncWaitData2(sign, this._remove, default); - if (!this.m_waitDic.TryAdd(sign, waitDataAsyncSlim)) - { - return default; - } - return waitDataAsyncSlim; - } - - /// - /// 使用指定结果设置对应签名的等待操作。 - /// - /// 包含签名和结果数据的对象。 - /// 如果成功设置等待操作则返回;否则返回 - /// - /// 此方法根据结果对象的签名查找对应的等待数据,并设置其结果。 - /// 设置成功后,等待数据会从池中移除,正在等待的任务会被完成。 - /// 如果找不到对应签名的等待数据,则返回。 - /// - public bool Set(T result) - { - if (this.m_waitDic.TryRemove(result.Sign, out var waitDataAsync)) - { - waitDataAsync.Set(result); - return true; - } - return false; - } - - /// - /// 尝试获取指定签名的异步等待数据。 - /// - /// 要查找的签名。 - /// 输出参数,如果找到则返回对应的等待数据;否则为。 - /// 如果找到指定签名的等待数据则返回;否则返回 - /// - /// 此方法允许查询池中是否存在特定签名的等待数据,而不会修改池的状态。 - /// 适用于需要检查等待状态或获取等待数据进行进一步操作的场景。 - /// - public bool TryGetDataAsync(int sign, out AsyncWaitData2 waitDataAsync) - { - return this.m_waitDic.TryGetValue(sign, out waitDataAsync); - } - - /// - /// 生成下一个可用的唯一签名。 - /// - /// 生成的唯一签名值。 - /// - /// 使用原子递增操作确保签名的唯一性和线程安全性。 - /// 当签名达到最大值时,会重新开始分配以避免溢出。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetSign() - { - while (true) - { - var currentSign = this.m_currentSign; - var nextSign = currentSign >= this.m_maxSign ? this.m_minSign : currentSign + 1; - - if (Interlocked.CompareExchange(ref this.m_currentSign, nextSign, currentSign) == currentSign) - { - return nextSign; - } - // 如果CAS失败,继续重试 - } - } - - /// - /// 从池中移除指定签名的等待数据。 - /// - /// 要移除的签名。 - /// - /// 此方法由等待数据在释放时自动调用,确保池中不会保留已完成或已取消的等待对象。 - /// - private void Remove(int sign) - { - this.m_waitDic.TryRemove(sign, out _); - } - } - - public sealed class AsyncWaitData2 : DisposableObject, IValueTaskSource - { - // ManualResetValueTaskSourceCore 是一个结构体,避免了额外托管对象分配,但需要配合 token 使用。 - private ManualResetValueTaskSourceCore _core; // 核心结构体,不会分配额外对象 - - // 缓存的移除回调,由 WaitHandlePool 构造时传入,避免每次分配委托。 - private readonly Action _remove; - - // 挂起时的临时数据 - private readonly T _pendingData; - - // 完成时的数据 - private T _completedData; - - // 当前等待状态(成功/取消/未完成等) - private WaitDataStatus _status; - private CancellationTokenRegistration Registration; - - /// - /// 使用指定签名和移除回调初始化一个新的 实例。 - /// - /// 此等待项对应的签名(用于在池中查找)。 - /// 完成或释放时调用的回调,用于将此实例从等待池中移除。 - /// 可选的挂起数据,当创建时可以携带一个初始占位数据。 - public AsyncWaitData2(int sign, Action remove, T pendingData) - { - this.Sign = sign; - this._remove = remove; - this._pendingData = pendingData; - this._core.RunContinuationsAsynchronously = true; // 确保续体异步执行,避免潜在的栈内联执行问题 - } - - /// - /// 获取此等待项的签名标识。 - /// - public int Sign { get; } - - /// - /// 获取挂起时的原始数据(如果在创建时传入)。 - /// - public T PendingData => this._pendingData; - - /// - /// 获取已完成时的返回数据。 - /// - public T CompletedData => this._completedData; - - /// - /// 获取当前等待状态(例如:Success、Canceled 等)。 - /// - public WaitDataStatus Status => this._status; - - /// - /// 取消当前等待,标记为已取消并触发等待任务的异常(OperationCanceledException)。 - /// - public void Cancel() - { - this.Set(WaitDataStatus.Canceled, default!); - } - - /// - /// 将等待项设置为成功并携带结果数据。 - /// - /// 要设置的完成数据。 - public void Set(T result) - { - this.Set(WaitDataStatus.Success, result); - } - - /// - /// 设置等待项的状态和数据,并完成对应的 ValueTask。 - /// - /// 要设置的状态。 - /// 要设置的完成数据。 - public void Set(WaitDataStatus status, T result) - { - this._status = status; - this._completedData = result; - - if (status == WaitDataStatus.Canceled) - this._core.SetException(new OperationCanceledException()); - else - this._core.SetResult(result); - } - - /// - /// 异步等待此项完成,返回一个 ,可传入取消令牌以取消等待。 - /// - /// 可选的取消令牌。若触发则会调用 。 - /// 表示等待状态的 ValueTask。 - public ValueTask WaitAsync(CancellationToken cancellationToken = default) - { - if (cancellationToken.CanBeCanceled) - { - this.Registration = cancellationToken.Register(this.Cancel); - } - - return new ValueTask(this, this._core.Version); - } - - /// - /// 从核心获取结果(显式接口实现)。 - /// 注意:此方法由 ValueTask 基础设施调用,不应直接在用户代码中调用。 - /// - WaitDataStatus IValueTaskSource.GetResult(short token) - { - this._core.GetResult(token); - return this._status; - } - - /// - /// 获取当前 ValueTask 源的状态(显式接口实现)。 - /// - ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) - => this._core.GetStatus(token); - - /// - /// 注册续体(显式接口实现)。 - /// 注意:flags 可以控制是否捕获上下文等行为。 - /// - void IValueTaskSource.OnCompleted(Action continuation, object? state, - short token, ValueTaskSourceOnCompletedFlags flags) - => this._core.OnCompleted(continuation, state, token, flags); - - /// - /// 释放托管资源时调用,会触发传入的移除回调,从所在的等待池中移除此等待项。 - /// - /// 是否为显式释放。 - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.Registration.Dispose(); - this._remove(this.Sign); - } - base.Dispose(disposing); - } - } - -} diff --git a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/TimeoutBenchmark.cs b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/TimeoutBenchmark.cs index f0565f001..225a1c64c 100644 --- a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/TimeoutBenchmark.cs +++ b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/TimeoutBenchmark.cs @@ -11,6 +11,7 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Diagnosers; +using ThingsGateway.NewLife; using ThingsGateway.NewLife.Collections; namespace ThingsGateway.Foundation; @@ -47,7 +48,7 @@ public class TimeoutBenchmark var _reusableTimeout = _reusableTimeouts.Get(); try { - await Task.Delay(5, _reusableTimeout.GetTokenSource(10, otherCts.Token).Token).ConfigureAwait(false); // 模拟工作 + await Task.Delay(5, _reusableTimeout.GetTokenSource(10, otherCts.Token)).ConfigureAwait(false); // 模拟工作 } finally {