mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 10:50:48 +08:00
feat: 并发字典替换为 NonBlockingDictionary 类型
This commit is contained in:
@@ -20,7 +20,7 @@ namespace ThingsGateway.Admin.Application;
|
|||||||
/// <typeparam name="TEntry"></typeparam>
|
/// <typeparam name="TEntry"></typeparam>
|
||||||
public class EventService<TEntry> : IEventService<TEntry>, IDisposable
|
public class EventService<TEntry> : IEventService<TEntry>, IDisposable
|
||||||
{
|
{
|
||||||
private ConcurrentDictionary<string, Func<TEntry, Task>> Cache = new();
|
private NonBlockingDictionary<string, Func<TEntry, Task>> Cache = new();
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
@@ -82,7 +82,7 @@ public static class ObjectExtensions
|
|||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="dic">字典</param>
|
/// <param name="dic">字典</param>
|
||||||
/// <param name="newDic">新字典</param>
|
/// <param name="newDic">新字典</param>
|
||||||
internal static void AddOrUpdate<T>(this ConcurrentDictionary<string, T> dic, Dictionary<string, T> newDic)
|
internal static void AddOrUpdate<T>(this NonBlockingDictionary<string, T> dic, Dictionary<string, T> newDic)
|
||||||
{
|
{
|
||||||
foreach (var (key, value) in newDic)
|
foreach (var (key, value) in newDic)
|
||||||
{
|
{
|
||||||
|
@@ -205,7 +205,7 @@ public static class ObjectExtensions
|
|||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="dic">字典</param>
|
/// <param name="dic">字典</param>
|
||||||
/// <param name="newDic">新字典</param>
|
/// <param name="newDic">新字典</param>
|
||||||
internal static void AddOrUpdate<T>(this ConcurrentDictionary<string, T> dic, Dictionary<string, T> newDic)
|
internal static void AddOrUpdate<T>(this NonBlockingDictionary<string, T> dic, Dictionary<string, T> newDic)
|
||||||
{
|
{
|
||||||
foreach (var (key, value) in newDic)
|
foreach (var (key, value) in newDic)
|
||||||
{
|
{
|
||||||
|
@@ -94,7 +94,7 @@ public static class AspNetCoreBuilderServiceCollectionExtensions
|
|||||||
/// <param name="mvcBuilder"></param>
|
/// <param name="mvcBuilder"></param>
|
||||||
/// <param name="configure"></param>
|
/// <param name="configure"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IMvcBuilder AddFromConvertBinding(this IMvcBuilder mvcBuilder, Action<ConcurrentDictionary<Type, Type>> configure = default)
|
public static IMvcBuilder AddFromConvertBinding(this IMvcBuilder mvcBuilder, Action<NonBlockingDictionary<Type, Type>> configure = default)
|
||||||
{
|
{
|
||||||
mvcBuilder.Services.AddFromConvertBinding(configure);
|
mvcBuilder.Services.AddFromConvertBinding(configure);
|
||||||
|
|
||||||
@@ -107,13 +107,13 @@ public static class AspNetCoreBuilderServiceCollectionExtensions
|
|||||||
/// <param name="services"></param>
|
/// <param name="services"></param>
|
||||||
/// <param name="configure"></param>
|
/// <param name="configure"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddFromConvertBinding(this IServiceCollection services, Action<ConcurrentDictionary<Type, Type>> configure = default)
|
public static IServiceCollection AddFromConvertBinding(this IServiceCollection services, Action<NonBlockingDictionary<Type, Type>> configure = default)
|
||||||
{
|
{
|
||||||
// 非 Web 环境跳过注册
|
// 非 Web 环境跳过注册
|
||||||
if (App.WebHostEnvironment == default) return services;
|
if (App.WebHostEnvironment == default) return services;
|
||||||
|
|
||||||
// 定义模型绑定转换器集合
|
// 定义模型绑定转换器集合
|
||||||
var modelBinderConverts = new ConcurrentDictionary<Type, Type>();
|
var modelBinderConverts = new NonBlockingDictionary<Type, Type>();
|
||||||
modelBinderConverts.TryAdd(typeof(DateTime), typeof(DateTimeModelConvertBinder));
|
modelBinderConverts.TryAdd(typeof(DateTime), typeof(DateTimeModelConvertBinder));
|
||||||
modelBinderConverts.TryAdd(typeof(DateTimeOffset), typeof(DateTimeOffsetModelConvertBinder));
|
modelBinderConverts.TryAdd(typeof(DateTimeOffset), typeof(DateTimeOffsetModelConvertBinder));
|
||||||
|
|
||||||
|
@@ -27,13 +27,13 @@ public class FromConvertBinder : IModelBinder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义模型绑定转换器集合
|
/// 定义模型绑定转换器集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<Type, Type> _modelBinderConverts;
|
private readonly NonBlockingDictionary<Type, Type> _modelBinderConverts;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
|
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
|
||||||
public FromConvertBinder(ConcurrentDictionary<Type, Type> modelBinderConverts)
|
public FromConvertBinder(NonBlockingDictionary<Type, Type> modelBinderConverts)
|
||||||
{
|
{
|
||||||
_modelBinderConverts = modelBinderConverts;
|
_modelBinderConverts = modelBinderConverts;
|
||||||
}
|
}
|
||||||
|
@@ -28,13 +28,13 @@ public class FromConvertBinderProvider : IModelBinderProvider
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义模型绑定转换器集合
|
/// 定义模型绑定转换器集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<Type, Type> _modelBinderConverts;
|
private readonly NonBlockingDictionary<Type, Type> _modelBinderConverts;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
|
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
|
||||||
public FromConvertBinderProvider(ConcurrentDictionary<Type, Type> modelBinderConverts)
|
public FromConvertBinderProvider(NonBlockingDictionary<Type, Type> modelBinderConverts)
|
||||||
{
|
{
|
||||||
_modelBinderConverts = modelBinderConverts;
|
_modelBinderConverts = modelBinderConverts;
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@ public static class DataValidator
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证类型正则表达式
|
/// 验证类型正则表达式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<string, ValidationItemMetadataAttribute> ValidationItemMetadatas;
|
private static readonly NonBlockingDictionary<string, ValidationItemMetadataAttribute> ValidationItemMetadatas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
@@ -57,7 +57,7 @@ public static class DataValidator
|
|||||||
ValidationItemMetadatas = GetValidationValidationItemMetadatas();
|
ValidationItemMetadatas = GetValidationValidationItemMetadatas();
|
||||||
|
|
||||||
// 缓存所有正则表达式
|
// 缓存所有正则表达式
|
||||||
GetValidationTypeValidationItemMetadataCached = new ConcurrentDictionary<object, (string, ValidationItemMetadataAttribute)>();
|
GetValidationTypeValidationItemMetadataCached = new NonBlockingDictionary<object, (string, ValidationItemMetadataAttribute)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -203,7 +203,7 @@ public static class DataValidator
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取验证类型验证Item集合
|
/// 获取验证类型验证Item集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<object, (string, ValidationItemMetadataAttribute)> GetValidationTypeValidationItemMetadataCached;
|
private static readonly NonBlockingDictionary<object, (string, ValidationItemMetadataAttribute)> GetValidationTypeValidationItemMetadataCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取验证类型正则表达式(需要缓存)
|
/// 获取验证类型正则表达式(需要缓存)
|
||||||
@@ -267,9 +267,9 @@ public static class DataValidator
|
|||||||
/// 获取验证类型所有有效的正则表达式
|
/// 获取验证类型所有有效的正则表达式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static ConcurrentDictionary<string, ValidationItemMetadataAttribute> GetValidationValidationItemMetadatas()
|
private static NonBlockingDictionary<string, ValidationItemMetadataAttribute> GetValidationValidationItemMetadatas()
|
||||||
{
|
{
|
||||||
var vaidationItems = new ConcurrentDictionary<string, ValidationItemMetadataAttribute>();
|
var vaidationItems = new NonBlockingDictionary<string, ValidationItemMetadataAttribute>();
|
||||||
|
|
||||||
// 查找所有 [ValidationMessageType] 类型中的 [ValidationMessage] 消息定义
|
// 查找所有 [ValidationMessageType] 类型中的 [ValidationMessage] 消息定义
|
||||||
var customErrorMessages = ValidationMessageTypes.SelectMany(u => u.GetFields()
|
var customErrorMessages = ValidationMessageTypes.SelectMany(u => u.GetFields()
|
||||||
|
@@ -353,7 +353,7 @@ public static class DependencyInjectionServiceCollectionExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类型名称集合
|
/// 类型名称集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<string, Type> TypeNamedCollection;
|
private static readonly NonBlockingDictionary<string, Type> TypeNamedCollection;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建代理方法
|
/// 创建代理方法
|
||||||
@@ -374,7 +374,7 @@ public static class DependencyInjectionServiceCollectionExtensions
|
|||||||
GlobalServiceProxyType = App.EffectiveTypes
|
GlobalServiceProxyType = App.EffectiveTypes
|
||||||
.FirstOrDefault(u => typeof(AspectDispatchProxy).IsAssignableFrom(u) && typeof(IGlobalDispatchProxy).IsAssignableFrom(u) && u.IsClass && !u.IsInterface && !u.IsAbstract);
|
.FirstOrDefault(u => typeof(AspectDispatchProxy).IsAssignableFrom(u) && typeof(IGlobalDispatchProxy).IsAssignableFrom(u) && u.IsClass && !u.IsInterface && !u.IsAbstract);
|
||||||
|
|
||||||
TypeNamedCollection = new ConcurrentDictionary<string, Type>();
|
TypeNamedCollection = new NonBlockingDictionary<string, Type>();
|
||||||
DispatchCreateMethod = typeof(AspectDispatchProxy).GetMethod(nameof(AspectDispatchProxy.Create));
|
DispatchCreateMethod = typeof(AspectDispatchProxy).GetMethod(nameof(AspectDispatchProxy.Create));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,21 +28,21 @@ internal static class Penetrates
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 请求动词映射字典
|
/// 请求动词映射字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, string> VerbToHttpMethods { get; private set; }
|
internal static NonBlockingDictionary<string, string> VerbToHttpMethods { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控制器排序集合
|
/// 控制器排序集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, (string, int, Type)> ControllerOrderCollection { get; set; }
|
internal static NonBlockingDictionary<string, (string, int, Type)> ControllerOrderCollection { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static Penetrates()
|
static Penetrates()
|
||||||
{
|
{
|
||||||
ControllerOrderCollection = new ConcurrentDictionary<string, (string, int, Type)>();
|
ControllerOrderCollection = new NonBlockingDictionary<string, (string, int, Type)>();
|
||||||
|
|
||||||
VerbToHttpMethods = new ConcurrentDictionary<string, string>
|
VerbToHttpMethods = new NonBlockingDictionary<string, string>
|
||||||
{
|
{
|
||||||
["post"] = "POST",
|
["post"] = "POST",
|
||||||
["add"] = "POST",
|
["add"] = "POST",
|
||||||
@@ -67,13 +67,13 @@ internal static class Penetrates
|
|||||||
["patch"] = "PATCH"
|
["patch"] = "PATCH"
|
||||||
};
|
};
|
||||||
|
|
||||||
//IsApiControllerCached = new ConcurrentDictionary<Type, bool>();
|
//IsApiControllerCached = new NonBlockingDictionary<Type, bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <summary>
|
///// <summary>
|
||||||
///// <see cref="IsApiController(Type)"/> 缓存集合
|
///// <see cref="IsApiController(Type)"/> 缓存集合
|
||||||
///// </summary>
|
///// </summary>
|
||||||
//private static readonly ConcurrentDictionary<Type, bool> IsApiControllerCached;
|
//private static readonly NonBlockingDictionary<Type, bool> IsApiControllerCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是Api控制器
|
/// 是否是Api控制器
|
||||||
|
@@ -61,7 +61,7 @@ internal sealed class EventBusHostedService : BackgroundService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 事件处理程序集合
|
/// 事件处理程序集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<EventHandlerWrapper, EventHandlerWrapper> _eventHandlers = new();
|
private readonly NonBlockingDictionary<EventHandlerWrapper, EventHandlerWrapper> _eventHandlers = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
|
@@ -31,7 +31,7 @@ public static class Oops
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 方法错误异常特性
|
/// 方法错误异常特性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<MethodBase, MethodIfException> _errorMethods;
|
private static readonly NonBlockingDictionary<MethodBase, MethodIfException> _errorMethods;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 错误代码类型
|
/// 错误代码类型
|
||||||
@@ -41,7 +41,7 @@ public static class Oops
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 错误消息字典
|
/// 错误消息字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<string, string> _errorCodeMessages;
|
private static readonly NonBlockingDictionary<string, string> _errorCodeMessages;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 友好异常设置
|
/// 友好异常设置
|
||||||
@@ -53,7 +53,7 @@ public static class Oops
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static Oops()
|
static Oops()
|
||||||
{
|
{
|
||||||
_errorMethods = new ConcurrentDictionary<MethodBase, MethodIfException>();
|
_errorMethods = new NonBlockingDictionary<MethodBase, MethodIfException>();
|
||||||
_friendlyExceptionSettings = App.GetConfig<FriendlyExceptionSettingsOptions>("FriendlyExceptionSettings", true);
|
_friendlyExceptionSettings = App.GetConfig<FriendlyExceptionSettingsOptions>("FriendlyExceptionSettings", true);
|
||||||
_errorCodeTypes = GetErrorCodeTypes();
|
_errorCodeTypes = GetErrorCodeTypes();
|
||||||
_errorCodeMessages = GetErrorCodeMessages();
|
_errorCodeMessages = GetErrorCodeMessages();
|
||||||
@@ -258,9 +258,9 @@ public static class Oops
|
|||||||
/// 获取所有错误消息
|
/// 获取所有错误消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static ConcurrentDictionary<string, string> GetErrorCodeMessages()
|
private static NonBlockingDictionary<string, string> GetErrorCodeMessages()
|
||||||
{
|
{
|
||||||
var defaultErrorCodeMessages = new ConcurrentDictionary<string, string>();
|
var defaultErrorCodeMessages = new NonBlockingDictionary<string, string>();
|
||||||
|
|
||||||
// 查找所有 [ErrorCodeType] 类型中的 [ErrorCodeMetadata] 元数据定义
|
// 查找所有 [ErrorCodeType] 类型中的 [ErrorCodeMetadata] 元数据定义
|
||||||
var errorCodeMessages = _errorCodeTypes.SelectMany(u => u.GetFields().Where(u => u.IsDefined(typeof(ErrorCodeItemMetadataAttribute))))
|
var errorCodeMessages = _errorCodeTypes.SelectMany(u => u.GetFields().Where(u => u.IsDefined(typeof(ErrorCodeItemMetadataAttribute))))
|
||||||
|
@@ -23,7 +23,7 @@ public static class ILoggerExtensions
|
|||||||
/// 设置日志上下文
|
/// 设置日志上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param>
|
/// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IDisposable ScopeContext(this ILogger logger, IDictionary<string, object> properties)
|
public static IDisposable ScopeContext(this ILogger logger, IDictionary<string, object> properties)
|
||||||
{
|
{
|
||||||
|
@@ -82,7 +82,7 @@ public static class StringLoggingExtensions
|
|||||||
/// 配置日志上下文
|
/// 配置日志上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param>
|
/// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static StringLoggingPart ScopeContext(this string message, IDictionary<string, object> properties)
|
public static StringLoggingPart ScopeContext(this string message, IDictionary<string, object> properties)
|
||||||
{
|
{
|
||||||
|
@@ -44,7 +44,7 @@ public sealed class FileLoggerProvider : ILoggerProvider, ISupportExternalScope
|
|||||||
/// 记录日志所有滚动文件名
|
/// 记录日志所有滚动文件名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>只有 MaxRollingFiles 和 FileSizeLimitBytes 大于 0 有效</remarks>
|
/// <remarks>只有 MaxRollingFiles 和 FileSizeLimitBytes 大于 0 有效</remarks>
|
||||||
internal readonly ConcurrentDictionary<string, FileInfo> _rollingFileNames = new();
|
internal readonly NonBlockingDictionary<string, FileInfo> _rollingFileNames = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件日志写入器
|
/// 文件日志写入器
|
||||||
|
@@ -94,7 +94,7 @@ public sealed partial class StringLoggingPart
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置日志上下文
|
/// 配置日志上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param>
|
/// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public StringLoggingPart ScopeContext(IDictionary<string, object> properties)
|
public StringLoggingPart ScopeContext(IDictionary<string, object> properties)
|
||||||
{
|
{
|
||||||
|
@@ -57,7 +57,7 @@ public static class Log
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置日志上下文
|
/// 配置日志上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param>
|
/// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static (ILogger logger, IDisposable scope) ScopeContext(IDictionary<string, object> properties)
|
public static (ILogger logger, IDisposable scope) ScopeContext(IDictionary<string, object> properties)
|
||||||
{
|
{
|
||||||
|
@@ -21,7 +21,7 @@ internal sealed class JobCancellationToken : IJobCancellationToken
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取消作业执行 Token 集合
|
/// 取消作业执行 Token 集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancellationTokenSources;
|
private readonly NonBlockingDictionary<string, CancellationTokenSource> _cancellationTokenSources;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作业调度器日志服务
|
/// 作业调度器日志服务
|
||||||
|
@@ -167,7 +167,7 @@ public partial class JobDetail
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 带命名规则的数据库列名
|
/// 带命名规则的数据库列名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取数据库列名
|
/// 获取数据库列名
|
||||||
|
@@ -65,7 +65,7 @@ internal sealed partial class SchedulerFactory : ISchedulerFactory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作业计划集合
|
/// 作业计划集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<string, Scheduler> _schedulers = new();
|
private readonly NonBlockingDictionary<string, Scheduler> _schedulers = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作业计划构建器集合
|
/// 作业计划构建器集合
|
||||||
|
@@ -380,7 +380,7 @@ public partial class Trigger
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 带命名规则的数据库列名
|
/// 带命名规则的数据库列名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取数据库列名
|
/// 获取数据库列名
|
||||||
|
@@ -83,11 +83,11 @@ public static class SpecificationDocumentBuilder
|
|||||||
|
|
||||||
// 初始化常量
|
// 初始化常量
|
||||||
_groupOrderRegex = new Regex(@"@(?<order>[0-9]+$)");
|
_groupOrderRegex = new Regex(@"@(?<order>[0-9]+$)");
|
||||||
GetActionGroupsCached = new ConcurrentDictionary<MethodInfo, IEnumerable<GroupExtraInfo>>();
|
GetActionGroupsCached = new NonBlockingDictionary<MethodInfo, IEnumerable<GroupExtraInfo>>();
|
||||||
GetControllerGroupsCached = new ConcurrentDictionary<Type, IEnumerable<GroupExtraInfo>>();
|
GetControllerGroupsCached = new NonBlockingDictionary<Type, IEnumerable<GroupExtraInfo>>();
|
||||||
GetGroupOpenApiInfoCached = new ConcurrentDictionary<string, SpecificationOpenApiInfo>();
|
GetGroupOpenApiInfoCached = new NonBlockingDictionary<string, SpecificationOpenApiInfo>();
|
||||||
GetControllerTagCached = new ConcurrentDictionary<ControllerActionDescriptor, string>();
|
GetControllerTagCached = new NonBlockingDictionary<ControllerActionDescriptor, string>();
|
||||||
GetActionTagCached = new ConcurrentDictionary<ApiDescription, string>();
|
GetActionTagCached = new NonBlockingDictionary<ApiDescription, string>();
|
||||||
|
|
||||||
// 默认分组,支持多个逗号分割
|
// 默认分组,支持多个逗号分割
|
||||||
DocumentGroupExtras = new List<GroupExtraInfo> { ResolveGroupExtraInfo(_specificationDocumentSettings.DefaultGroupName) };
|
DocumentGroupExtras = new List<GroupExtraInfo> { ResolveGroupExtraInfo(_specificationDocumentSettings.DefaultGroupName) };
|
||||||
@@ -143,7 +143,7 @@ public static class SpecificationDocumentBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取分组信息缓存集合
|
/// 获取分组信息缓存集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<string, SpecificationOpenApiInfo> GetGroupOpenApiInfoCached;
|
private static readonly NonBlockingDictionary<string, SpecificationOpenApiInfo> GetGroupOpenApiInfoCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取分组配置信息
|
/// 获取分组配置信息
|
||||||
@@ -738,7 +738,7 @@ public static class SpecificationDocumentBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取控制器组缓存集合
|
/// 获取控制器组缓存集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<Type, IEnumerable<GroupExtraInfo>> GetControllerGroupsCached;
|
private static readonly NonBlockingDictionary<Type, IEnumerable<GroupExtraInfo>> GetControllerGroupsCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取控制器分组列表
|
/// 获取控制器分组列表
|
||||||
@@ -773,7 +773,7 @@ public static class SpecificationDocumentBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="GetActionGroups(MethodInfo)"/> 缓存集合
|
/// <see cref="GetActionGroups(MethodInfo)"/> 缓存集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<MethodInfo, IEnumerable<GroupExtraInfo>> GetActionGroupsCached;
|
private static readonly NonBlockingDictionary<MethodInfo, IEnumerable<GroupExtraInfo>> GetActionGroupsCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取动作方法分组列表
|
/// 获取动作方法分组列表
|
||||||
@@ -808,7 +808,7 @@ public static class SpecificationDocumentBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
|
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<ControllerActionDescriptor, string> GetControllerTagCached;
|
private static readonly NonBlockingDictionary<ControllerActionDescriptor, string> GetControllerTagCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取控制器标签
|
/// 获取控制器标签
|
||||||
@@ -835,7 +835,7 @@ public static class SpecificationDocumentBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
|
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ConcurrentDictionary<ApiDescription, string> GetActionTagCached;
|
private static readonly NonBlockingDictionary<ApiDescription, string> GetActionTagCached;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取动作方法标签
|
/// 获取动作方法标签
|
||||||
|
@@ -51,12 +51,12 @@ public static class UnifyContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 规范化结果提供器
|
/// 规范化结果提供器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, UnifyMetadata> UnifyProviders = new();
|
internal static NonBlockingDictionary<string, UnifyMetadata> UnifyProviders = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 规范化序列化配置
|
/// 规范化序列化配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, object> UnifySerializerSettings = new();
|
internal static NonBlockingDictionary<string, object> UnifySerializerSettings = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取异常元数据
|
/// 获取异常元数据
|
||||||
|
@@ -14,7 +14,7 @@ using System.Collections.Concurrent;
|
|||||||
namespace ThingsGateway.Extension;
|
namespace ThingsGateway.Extension;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="ConcurrentDictionary{TKey, TValue}" /> 拓展类
|
/// <see cref="NonBlockingDictionary{TKey, TValue}" /> 拓展类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ConcurrentDictionaryExtensions
|
internal static class ConcurrentDictionaryExtensions
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@ internal static class ConcurrentDictionaryExtensions
|
|||||||
/// <typeparam name="TKey">字典键类型</typeparam>
|
/// <typeparam name="TKey">字典键类型</typeparam>
|
||||||
/// <typeparam name="TValue">字典值类型</typeparam>
|
/// <typeparam name="TValue">字典值类型</typeparam>
|
||||||
/// <param name="dictionary">
|
/// <param name="dictionary">
|
||||||
/// <see cref="ConcurrentDictionary{TKey, TValue}" />
|
/// <see cref="NonBlockingDictionary{TKey, TValue}" />
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="key">
|
/// <param name="key">
|
||||||
/// <typeparamref name="TKey" />
|
/// <typeparamref name="TKey" />
|
||||||
@@ -36,7 +36,7 @@ internal static class ConcurrentDictionaryExtensions
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// <see cref="bool" />
|
/// <see cref="bool" />
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal static bool TryUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary
|
internal static bool TryUpdate<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dictionary
|
||||||
, TKey key
|
, TKey key
|
||||||
, Func<TValue, TValue> updateFactory
|
, Func<TValue, TValue> updateFactory
|
||||||
, out TValue? value)
|
, out TValue? value)
|
||||||
|
@@ -241,7 +241,7 @@ internal static class IDictionaryExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>其中键是由值通过给定的选择器函数生成的。</remarks>
|
/// <remarks>其中键是由值通过给定的选择器函数生成的。</remarks>
|
||||||
/// <param name="dictionary">
|
/// <param name="dictionary">
|
||||||
/// <see cref="ConcurrentDictionary{TKey, TValue}" />
|
/// <see cref="NonBlockingDictionary{TKey, TValue}" />
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="values">
|
/// <param name="values">
|
||||||
/// <see cref="IEnumerable{T}" />
|
/// <see cref="IEnumerable{T}" />
|
||||||
@@ -249,7 +249,7 @@ internal static class IDictionaryExtensions
|
|||||||
/// <param name="keySelector">键选择器</param>
|
/// <param name="keySelector">键选择器</param>
|
||||||
/// <typeparam name="TKey">字典键类型</typeparam>
|
/// <typeparam name="TKey">字典键类型</typeparam>
|
||||||
/// <typeparam name="TValue">字典值类型</typeparam>
|
/// <typeparam name="TValue">字典值类型</typeparam>
|
||||||
internal static void TryAdd<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary,
|
internal static void TryAdd<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dictionary,
|
||||||
IEnumerable<TValue>? values, Func<TValue, TKey> keySelector)
|
IEnumerable<TValue>? values, Func<TValue, TKey> keySelector)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
|
@@ -21,20 +21,20 @@ internal sealed class CoreOptions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 已注册的组件元数据集合
|
/// 已注册的组件元数据集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly ConcurrentDictionary<string, ComponentMetadata> _metadataOfRegistered;
|
internal readonly NonBlockingDictionary<string, ComponentMetadata> _metadataOfRegistered;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 子选项集合
|
/// 子选项集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly ConcurrentDictionary<Type, object> _optionsInstances;
|
internal readonly NonBlockingDictionary<Type, object> _optionsInstances;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <inheritdoc cref="CoreOptions" />
|
/// <inheritdoc cref="CoreOptions" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal CoreOptions()
|
internal CoreOptions()
|
||||||
{
|
{
|
||||||
_optionsInstances = new ConcurrentDictionary<Type, object>();
|
_optionsInstances = new NonBlockingDictionary<Type, object>();
|
||||||
_metadataOfRegistered = new ConcurrentDictionary<string, ComponentMetadata>(StringComparer.OrdinalIgnoreCase);
|
_metadataOfRegistered = new NonBlockingDictionary<string, ComponentMetadata>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
EntryComponentTypes = [];
|
EntryComponentTypes = [];
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@ public sealed class ObjectPropertyGetter<T> where T : class
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象类型实例属性值访问器集合
|
/// 对象类型实例属性值访问器集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly ConcurrentDictionary<string, Func<object, object?>> _propertyGetters = new();
|
internal readonly NonBlockingDictionary<string, Func<object, object?>> _propertyGetters = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <inheritdoc cref="ObjectPropertyGetter{T}" />
|
/// <inheritdoc cref="ObjectPropertyGetter{T}" />
|
||||||
|
@@ -32,7 +32,7 @@ public sealed class ObjectPropertySetter<T> where T : class
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象类型实例属性值设置器集合
|
/// 对象类型实例属性值设置器集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly ConcurrentDictionary<string, Action<object, object?>> _propertySetters = new();
|
internal readonly NonBlockingDictionary<string, Action<object, object?>> _propertySetters = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <inheritdoc cref="ObjectPropertySetter{T}" />
|
/// <inheritdoc cref="ObjectPropertySetter{T}" />
|
||||||
|
@@ -27,7 +27,7 @@ public sealed class HttpDeclarativeBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合
|
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static readonly ConcurrentDictionary<Type, IHttpDeclarativeExtractor> _extractors = new([
|
internal static readonly NonBlockingDictionary<Type, IHttpDeclarativeExtractor> _extractors = new([
|
||||||
new(typeof(BaseAddressDeclarativeExtractor), new BaseAddressDeclarativeExtractor()),
|
new(typeof(BaseAddressDeclarativeExtractor), new BaseAddressDeclarativeExtractor()),
|
||||||
new(typeof(ValidationDeclarativeExtractor), new ValidationDeclarativeExtractor()),
|
new(typeof(ValidationDeclarativeExtractor), new ValidationDeclarativeExtractor()),
|
||||||
new(typeof(AutoSetHostHeaderDeclarativeExtractor), new AutoSetHostHeaderDeclarativeExtractor()),
|
new(typeof(AutoSetHostHeaderDeclarativeExtractor), new AutoSetHostHeaderDeclarativeExtractor()),
|
||||||
@@ -56,7 +56,7 @@ public sealed class HttpDeclarativeBuilder
|
|||||||
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合(冻结)
|
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合(冻结)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>该集合用于确保某些 HTTP 声明式提取器始终位于最后。</remarks>
|
/// <remarks>该集合用于确保某些 HTTP 声明式提取器始终位于最后。</remarks>
|
||||||
internal static readonly ConcurrentDictionary<Type, IFrozenHttpDeclarativeExtractor> _frozenExtractors = new([
|
internal static readonly NonBlockingDictionary<Type, IFrozenHttpDeclarativeExtractor> _frozenExtractors = new([
|
||||||
new(typeof(MultipartDeclarativeExtractor), new MultipartDeclarativeExtractor()),
|
new(typeof(MultipartDeclarativeExtractor), new MultipartDeclarativeExtractor()),
|
||||||
new(typeof(HttpMultipartFormDataBuilderDeclarativeExtractor),
|
new(typeof(HttpMultipartFormDataBuilderDeclarativeExtractor),
|
||||||
new HttpMultipartFormDataBuilderDeclarativeExtractor()),
|
new HttpMultipartFormDataBuilderDeclarativeExtractor()),
|
||||||
|
@@ -27,7 +27,7 @@ public class MessagePackContentProcessor : HttpContentProcessorBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// MessagePack 序列化器委托字典缓存
|
/// MessagePack 序列化器委托字典缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static readonly ConcurrentDictionary<Type, Func<object, byte[]>> _serializerCache = new();
|
internal static readonly NonBlockingDictionary<Type, Func<object, byte[]>> _serializerCache = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化 MessagePack 序列化器委托
|
/// 初始化 MessagePack 序列化器委托
|
||||||
|
@@ -23,7 +23,7 @@ public class MemoryCache : Cache
|
|||||||
{
|
{
|
||||||
#region 属性
|
#region 属性
|
||||||
/// <summary>缓存核心</summary>
|
/// <summary>缓存核心</summary>
|
||||||
protected ConcurrentDictionary<String, CacheItem> _cache = new();
|
protected NonBlockingDictionary<String, CacheItem> _cache = new();
|
||||||
|
|
||||||
/// <summary>容量。容量超标时,采用LRU机制删除,默认100_000</summary>
|
/// <summary>容量。容量超标时,采用LRU机制删除,默认100_000</summary>
|
||||||
public Int32 Capacity { get; set; } = 100_000;
|
public Int32 Capacity { get; set; } = 100_000;
|
||||||
@@ -379,7 +379,7 @@ public class MemoryCache : Cache
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override IDictionary<String, T> GetDictionary<T>(String key)
|
public override IDictionary<String, T> GetDictionary<T>(String key)
|
||||||
{
|
{
|
||||||
var item = GetOrAddItem(key, k => new ConcurrentDictionary<String, T>());
|
var item = GetOrAddItem(key, k => new NonBlockingDictionary<String, T>());
|
||||||
return item.Visit<IDictionary<String, T>>() ??
|
return item.Visit<IDictionary<String, T>>() ??
|
||||||
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IDictionary<String, T>)}");
|
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IDictionary<String, T>)}");
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
后续例程与使用说明均以Redis为例,各缓存实现类似。
|
后续例程与使用说明均以Redis为例,各缓存实现类似。
|
||||||
|
|
||||||
### 内存缓存 MemoryCache
|
### 内存缓存 MemoryCache
|
||||||
MemoryCache核心是并发字典ConcurrentDictionary,由于省去了序列化和网络通信,使得它具有千万级超高性能。
|
MemoryCache核心是并发字典NonBlockingDictionary,由于省去了序列化和网络通信,使得它具有千万级超高性能。
|
||||||
MemoryCache支持过期时间,默认容量10万个,未过期key超过该值后,每60秒根据LRU清理溢出部分。
|
MemoryCache支持过期时间,默认容量10万个,未过期key超过该值后,每60秒根据LRU清理溢出部分。
|
||||||
常用于进程内千万级以下数据缓存场景。
|
常用于进程内千万级以下数据缓存场景。
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ public static class CollectionHelper
|
|||||||
{
|
{
|
||||||
//if (collection == null) return null;
|
//if (collection == null) return null;
|
||||||
|
|
||||||
if (collection is ConcurrentDictionary<TKey, TValue> cdiv && cdiv.Keys is IList<TKey> list) return list;
|
if (collection is NonBlockingDictionary<TKey, TValue> cdiv && cdiv.Keys is IList<TKey> list) return list;
|
||||||
|
|
||||||
if (collection.Count == 0) return [];
|
if (collection.Count == 0) return [];
|
||||||
lock (collection)
|
lock (collection)
|
||||||
@@ -65,8 +65,8 @@ public static class CollectionHelper
|
|||||||
{
|
{
|
||||||
//if (collection == null) return null;
|
//if (collection == null) return null;
|
||||||
|
|
||||||
//if (collection is ConcurrentDictionary<TKey, TValue> cdiv) return cdiv.Values as IList<TValue>;
|
//if (collection is NonBlockingDictionary<TKey, TValue> cdiv) return cdiv.Values as IList<TValue>;
|
||||||
if (collection is ConcurrentDictionary<TKey, TValue> cdiv && cdiv.Values is IList<TValue> list) return list;
|
if (collection is NonBlockingDictionary<TKey, TValue> cdiv && cdiv.Values is IList<TValue> list) return list;
|
||||||
|
|
||||||
if (collection.Count == 0) return [];
|
if (collection.Count == 0) return [];
|
||||||
lock (collection)
|
lock (collection)
|
||||||
|
@@ -9,7 +9,7 @@ namespace ThingsGateway.NewLife.Collections;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class ConcurrentHashSet<T> : IEnumerable<T> where T : notnull
|
public class ConcurrentHashSet<T> : IEnumerable<T> where T : notnull
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<T, Byte> _dic = new();
|
private readonly NonBlockingDictionary<T, Byte> _dic = new();
|
||||||
|
|
||||||
/// <summary>是否空集合</summary>
|
/// <summary>是否空集合</summary>
|
||||||
public Boolean IsEmpty => _dic.IsEmpty;
|
public Boolean IsEmpty => _dic.IsEmpty;
|
||||||
|
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal abstract partial class DictionaryImpl<TKey, TKeyStore, TValue>
|
||||||
|
: DictionaryImpl<TKey, TValue>
|
||||||
|
{
|
||||||
|
internal override Snapshot GetSnapshot()
|
||||||
|
{
|
||||||
|
return new SnapshotImpl(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SnapshotImpl : Snapshot
|
||||||
|
{
|
||||||
|
private readonly DictionaryImpl<TKey, TKeyStore, TValue> _table;
|
||||||
|
|
||||||
|
public SnapshotImpl(DictionaryImpl<TKey, TKeyStore, TValue> dict)
|
||||||
|
{
|
||||||
|
this._table = dict;
|
||||||
|
|
||||||
|
// linearization point.
|
||||||
|
// if table is quiescent and has no copy in progress,
|
||||||
|
// we can simply iterate over its table.
|
||||||
|
while (_table._newTable != null)
|
||||||
|
{
|
||||||
|
// there is a copy in progress, finish it and try again
|
||||||
|
_table.HelpCopy(copy_all: true);
|
||||||
|
this._table = (DictionaryImpl<TKey, TKeyStore, TValue>)this._table._topDict._table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Count => _table.Count;
|
||||||
|
|
||||||
|
public override bool MoveNext()
|
||||||
|
{
|
||||||
|
var entries = this._table._entries;
|
||||||
|
while (_idx < entries.Length)
|
||||||
|
{
|
||||||
|
var nextEntry = entries[_idx++];
|
||||||
|
|
||||||
|
if (nextEntry.value != null)
|
||||||
|
{
|
||||||
|
var nextKstore = nextEntry.key;
|
||||||
|
if (nextKstore == null)
|
||||||
|
{
|
||||||
|
// slot was deleted.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_curKey = _table.keyFromEntry(nextKstore);
|
||||||
|
object nextV = _table.TryGetValue(_curKey);
|
||||||
|
if (nextV != null)
|
||||||
|
{
|
||||||
|
_curValue = _table.FromObjectValue(nextV);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_curKey = default;
|
||||||
|
_curValue = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
_idx = 0;
|
||||||
|
_curKey = default;
|
||||||
|
_curValue = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal abstract class DictionaryImpl
|
||||||
|
{
|
||||||
|
internal enum ValueMatch
|
||||||
|
{
|
||||||
|
Any, // sets new value unconditionally, used by index set and TryRemove(key)
|
||||||
|
NullOrDead, // set value if original value is null or dead, used by Add/TryAdd
|
||||||
|
NotNullOrDead, // set value if original value is alive, used by Remove
|
||||||
|
OldValue, // sets new value if old value matches
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class Prime
|
||||||
|
{
|
||||||
|
internal object originalValue;
|
||||||
|
|
||||||
|
public Prime(object originalValue)
|
||||||
|
{
|
||||||
|
this.originalValue = originalValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static readonly object TOMBSTONE = new object();
|
||||||
|
internal static readonly Prime TOMBPRIME = new Prime(TOMBSTONE);
|
||||||
|
internal static readonly object NULLVALUE = new object();
|
||||||
|
|
||||||
|
// represents a trivially copied empty entry
|
||||||
|
// we insert it in the old table during rehashing
|
||||||
|
// to reduce chances that more entries are added
|
||||||
|
protected const int TOMBPRIMEHASH = 1 << 31;
|
||||||
|
|
||||||
|
// we cannot distigush zero keys from uninitialized state
|
||||||
|
// so we force them to have this special hash instead
|
||||||
|
protected const int ZEROHASH = 1 << 30;
|
||||||
|
|
||||||
|
// all regular hashes have both these bits set
|
||||||
|
// to be different from either 0, TOMBPRIMEHASH or ZEROHASH
|
||||||
|
// having only these bits set in a case of Ref key means that the slot is permanently deleted.
|
||||||
|
protected const int SPECIAL_HASH_BITS = TOMBPRIMEHASH | ZEROHASH;
|
||||||
|
|
||||||
|
// Heuristic to decide if we have reprobed toooo many times. Running over
|
||||||
|
// the reprobe limit on a 'get' call acts as a 'miss'; on a 'put' call it
|
||||||
|
// can trigger a table resize. Several places must have exact agreement on
|
||||||
|
// what the reprobe_limit is, so we share it here.
|
||||||
|
protected const int REPROBE_LIMIT = 4;
|
||||||
|
protected const int REPROBE_LIMIT_SHIFT = 8;
|
||||||
|
|
||||||
|
protected static int ReprobeLimit(int lenMask)
|
||||||
|
{
|
||||||
|
// 1/2 of table with some extra
|
||||||
|
return REPROBE_LIMIT + (lenMask >> REPROBE_LIMIT_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool EntryValueNullOrDead(object entryValue)
|
||||||
|
{
|
||||||
|
return entryValue == null || entryValue == TOMBSTONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected static int ReduceHashToIndex(int fullHash, int lenMask)
|
||||||
|
{
|
||||||
|
var h = (uint)fullHash;
|
||||||
|
|
||||||
|
// xor-shift some upper bits down, in case if variations are mostly in high bits
|
||||||
|
// and scatter the bits a little to break up clusters if hashes are periodic (like 42, 43, 44, ...)
|
||||||
|
// long clusters can cause long reprobes. small clusters are ok though.
|
||||||
|
h ^= h >> 15;
|
||||||
|
h ^= h >> 8;
|
||||||
|
h += (h >> 3) * 2654435769u;
|
||||||
|
|
||||||
|
return (int)h & lenMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static object ToObjectValue<TValue>(TValue value)
|
||||||
|
{
|
||||||
|
if (default(TValue) != null)
|
||||||
|
{
|
||||||
|
return new Boxed<TValue>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object)value ?? NULLVALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,138 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal sealed class DictionaryImplBoxed<TKey, TValue>
|
||||||
|
: DictionaryImpl<TKey, Boxed<TKey>, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplBoxed(int capacity, NonBlockingDictionary<TKey, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplBoxed(int capacity, DictionaryImplBoxed<TKey, TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref Boxed<TKey> entryKey, TKey key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, new Boxed<TKey>(key), null);
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _keyComparer.Equals(key, entryKeyValue.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref Boxed<TKey> entryKey, Boxed<TKey> key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, null);
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _keyComparer.Equals(key.Value, entryKeyValue.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(TKey key, Boxed<TKey> entryKey)
|
||||||
|
{
|
||||||
|
//NOTE: slots are claimed in two stages - claim a hash, then set a key
|
||||||
|
// it is possible to observe a slot with a null key, but with hash already set
|
||||||
|
// that is not a match since the key is not yet in the table
|
||||||
|
if (entryKey == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _keyComparer.Equals(key, entryKey.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<TKey, Boxed<TKey>, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplBoxed<TKey, TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TKey keyFromEntry(Boxed<TKey> entryKey)
|
||||||
|
{
|
||||||
|
return entryKey.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode()
|
||||||
|
internal class Boxed<T>
|
||||||
|
{
|
||||||
|
// 0 - allow writes, 1 - someone is writing, 2 frozen.
|
||||||
|
public int writeStatus;
|
||||||
|
public T Value;
|
||||||
|
|
||||||
|
public Boxed(T key)
|
||||||
|
{
|
||||||
|
this.Value = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return EqualityComparer<T>.Default.Equals(this.Value, Unsafe.As<Boxed<T>>(obj).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool TryVolatileWrite(T value)
|
||||||
|
{
|
||||||
|
if (Interlocked.CompareExchange(ref writeStatus, 1, 0) == 0)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Volatile.Write(ref writeStatus, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool TryCompareExchange(T oldValue, T newValue, out bool changed)
|
||||||
|
{
|
||||||
|
changed = false;
|
||||||
|
if (Interlocked.CompareExchange(ref writeStatus, 1, 0) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EqualityComparer<T>.Default.Equals(Value, oldValue))
|
||||||
|
{
|
||||||
|
Value = newValue;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Volatile.Write(ref writeStatus, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal void Freeze()
|
||||||
|
{
|
||||||
|
// Wait for writers (1) to leave. Already 2 is ok, or set 0 -> 2.
|
||||||
|
while (Interlocked.CompareExchange(ref writeStatus, 2, 0) == 1) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode()
|
||||||
|
}
|
@@ -0,0 +1,143 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal sealed class DictionaryImplInt<TValue>
|
||||||
|
: DictionaryImpl<int, int, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplInt(int capacity, NonBlockingDictionary<int, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplInt(int capacity, DictionaryImplInt<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 & key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, 0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue || _keyComparer.Equals(key, entryKeyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(int key)
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
{
|
||||||
|
return ZEROHASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.hash(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(int key, int entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey || _keyComparer.Equals(key, entryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<int, int, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplInt<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int keyFromEntry(int entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class DictionaryImplIntNoComparer<TValue>
|
||||||
|
: DictionaryImpl<int, int, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplIntNoComparer(int capacity, NonBlockingDictionary<int, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplIntNoComparer(int capacity, DictionaryImplIntNoComparer<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref int entryKey, int key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 & key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, 0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline the base implementation to devirtualize calls to hash and keyEqual
|
||||||
|
internal override object TryGetValue(int key)
|
||||||
|
{
|
||||||
|
return base.TryGetValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(int key)
|
||||||
|
{
|
||||||
|
return (key == 0) ?
|
||||||
|
ZEROHASH :
|
||||||
|
key | SPECIAL_HASH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(int key, int entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<int, int, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplIntNoComparer<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int keyFromEntry(int entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,143 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal sealed class DictionaryImplLong<TValue>
|
||||||
|
: DictionaryImpl<long, long, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplLong(int capacity, NonBlockingDictionary<long, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplLong(int capacity, DictionaryImplLong<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 && key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, 0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue || _keyComparer.Equals(key, entryKeyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(long key)
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
{
|
||||||
|
return ZEROHASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.hash(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(long key, long entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey || _keyComparer.Equals(key, entryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<long, long, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplLong<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override long keyFromEntry(long entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class DictionaryImplLongNoComparer<TValue>
|
||||||
|
: DictionaryImpl<long, long, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplLongNoComparer(int capacity, NonBlockingDictionary<long, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplLongNoComparer(int capacity, DictionaryImplLongNoComparer<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref long entryKey, long key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 && key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, 0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline the base implementation to devirtualize calls to hash and keyEqual
|
||||||
|
internal override object TryGetValue(long key)
|
||||||
|
{
|
||||||
|
return base.TryGetValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(long key)
|
||||||
|
{
|
||||||
|
return (key == 0) ?
|
||||||
|
ZEROHASH :
|
||||||
|
key.GetHashCode() | SPECIAL_HASH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(long key, long entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<long, long, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplLongNoComparer<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override long keyFromEntry(long entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,143 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal sealed class DictionaryImplNint<TValue>
|
||||||
|
: DictionaryImpl<nint, nint, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplNint(int capacity, NonBlockingDictionary<nint, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplNint(int capacity, DictionaryImplNint<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 && key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, (nint)0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue || _keyComparer.Equals(key, entryKeyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(nint key)
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
{
|
||||||
|
return ZEROHASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.hash(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(nint key, nint entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey || _keyComparer.Equals(key, entryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<nint, nint, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplNint<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override nint keyFromEntry(nint entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class DictionaryImplNintNoComparer<TValue>
|
||||||
|
: DictionaryImpl<nint, nint, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplNintNoComparer(int capacity, NonBlockingDictionary<nint, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplNintNoComparer(int capacity, DictionaryImplNintNoComparer<TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref nint entryKey, nint key)
|
||||||
|
{
|
||||||
|
var entryKeyValue = entryKey;
|
||||||
|
//zero keys are claimed via hash
|
||||||
|
if (entryKeyValue == 0 && key != 0)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref entryKey, key, (nint)0);
|
||||||
|
if (entryKeyValue == 0)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key == entryKeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline the base implementation to devirtualize calls to hash and keyEqual
|
||||||
|
internal override object TryGetValue(nint key)
|
||||||
|
{
|
||||||
|
return base.TryGetValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(nint key)
|
||||||
|
{
|
||||||
|
return (key == 0) ?
|
||||||
|
ZEROHASH :
|
||||||
|
key.GetHashCode() | SPECIAL_HASH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(nint key, nint entryKey)
|
||||||
|
{
|
||||||
|
return key == entryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<nint, nint, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplNintNoComparer<TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override nint keyFromEntry(nint entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal sealed class DictionaryImplRef<TKey, TKeyStore, TValue>
|
||||||
|
: DictionaryImpl<TKey, TKey, TValue>
|
||||||
|
{
|
||||||
|
internal DictionaryImplRef(int capacity, NonBlockingDictionary<TKey, TValue> topDict)
|
||||||
|
: base(capacity, topDict)
|
||||||
|
{
|
||||||
|
Debug.Assert(!typeof(TKey).IsValueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DictionaryImplRef(int capacity, DictionaryImplRef<TKey, TKeyStore, TValue> other)
|
||||||
|
: base(capacity, other)
|
||||||
|
{
|
||||||
|
Debug.Assert(!typeof(TKey).IsValueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForPut(ref TKey entryKey, TKey key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryClaimSlotForCopy(ref TKey entryKey, TKey key)
|
||||||
|
{
|
||||||
|
return TryClaimSlot(ref entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryClaimSlot(ref TKey entryKey, TKey key)
|
||||||
|
{
|
||||||
|
ref object keyLocation = ref Unsafe.As<TKey, object>(ref entryKey);
|
||||||
|
object entryKeyValue = keyLocation;
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
entryKeyValue = Interlocked.CompareExchange(ref keyLocation, key, null);
|
||||||
|
if (entryKeyValue == null)
|
||||||
|
{
|
||||||
|
// claimed a new slot
|
||||||
|
this.allocatedSlotCount.Increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object)key == entryKeyValue ||
|
||||||
|
_keyComparer.Equals(key, Unsafe.As<object, TKey>(ref entryKeyValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline the base implementation to devirtualize calls to hash and keyEqual
|
||||||
|
internal override object TryGetValue(TKey key)
|
||||||
|
{
|
||||||
|
return base.TryGetValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int hash(TKey key)
|
||||||
|
{
|
||||||
|
return base.hash(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool keyEqual(TKey key, TKey entryKey)
|
||||||
|
{
|
||||||
|
if ((object)key == (object)entryKey)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: slots are claimed in two stages - claim a hash, then set a key
|
||||||
|
// it is possible to observe a slot with a null key, but with hash already set
|
||||||
|
// that is not a match since the key is not yet in the table
|
||||||
|
if (entryKey == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _keyComparer.Equals(entryKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DictionaryImpl<TKey, TKey, TValue> CreateNew(int capacity)
|
||||||
|
{
|
||||||
|
return new DictionaryImplRef<TKey, TKeyStore, TValue>(capacity, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TKey keyFromEntry(TKey entryKey)
|
||||||
|
{
|
||||||
|
return entryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal abstract class DictionaryImpl<TKey, TValue>
|
||||||
|
: DictionaryImpl
|
||||||
|
{
|
||||||
|
private readonly bool _valueIsValueType = typeof(TValue).IsValueType;
|
||||||
|
|
||||||
|
internal IEqualityComparer<TKey> _keyComparer;
|
||||||
|
|
||||||
|
internal abstract void Clear();
|
||||||
|
internal abstract int Count { get; }
|
||||||
|
|
||||||
|
internal abstract object TryGetValue(TKey key);
|
||||||
|
internal abstract bool PutIfMatch(TKey key, TValue newVal, ref TValue oldValue, ValueMatch match);
|
||||||
|
internal abstract bool RemoveIfMatch(TKey key, ref TValue oldValue, ValueMatch match);
|
||||||
|
internal abstract TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory);
|
||||||
|
|
||||||
|
internal abstract Snapshot GetSnapshot();
|
||||||
|
|
||||||
|
internal abstract class Snapshot
|
||||||
|
{
|
||||||
|
protected int _idx;
|
||||||
|
protected TKey _curKey;
|
||||||
|
protected TValue _curValue;
|
||||||
|
|
||||||
|
public abstract int Count { get; }
|
||||||
|
public abstract bool MoveNext();
|
||||||
|
public abstract void Reset();
|
||||||
|
|
||||||
|
internal DictionaryEntry Entry
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new DictionaryEntry(_curKey, _curValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal KeyValuePair<TKey, TValue> Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new KeyValuePair<TKey, TValue>(this._curKey, _curValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected TValue FromObjectValue(object obj)
|
||||||
|
{
|
||||||
|
// regular value type
|
||||||
|
if (default(TValue) != null)
|
||||||
|
{
|
||||||
|
return Unsafe.As<Boxed<TValue>>(obj).Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// null
|
||||||
|
if (obj == NULLVALUE)
|
||||||
|
{
|
||||||
|
return default(TValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref type
|
||||||
|
if (!_valueIsValueType)
|
||||||
|
{
|
||||||
|
return Unsafe.As<object, TValue>(ref obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nullable
|
||||||
|
return (TValue)obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scalable 32bit counter that can be used from multiple threads.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Counter32 : CounterBase
|
||||||
|
{
|
||||||
|
private class Cell
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = CACHE_LINE * 2 - OBJ_HEADER_SIZE)]
|
||||||
|
public struct SpacedCounter
|
||||||
|
{
|
||||||
|
[FieldOffset(CACHE_LINE - OBJ_HEADER_SIZE)]
|
||||||
|
public int count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpacedCounter counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// spaced out counters
|
||||||
|
private Cell[]? cells;
|
||||||
|
|
||||||
|
// default counter
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
// delayed estimated count
|
||||||
|
private int lastCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the value of the counter at the time of the call.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The value may miss in-progress updates if the counter is being concurrently modified.
|
||||||
|
/// </remarks>
|
||||||
|
public int Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var count = this.count;
|
||||||
|
var cells = this.cells;
|
||||||
|
|
||||||
|
if (cells != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cells.Length; i++)
|
||||||
|
{
|
||||||
|
var cell = cells[i];
|
||||||
|
if (cell != null)
|
||||||
|
{
|
||||||
|
count += cell.counter.count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the approximate value of the counter at the time of the call.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// EstimatedValue could be significantly cheaper to obtain, but may be slightly delayed.
|
||||||
|
/// </remarks>
|
||||||
|
public int EstimatedValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.cells == null)
|
||||||
|
{
|
||||||
|
return this.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curTicks = (uint)Environment.TickCount;
|
||||||
|
// more than a millisecond passed?
|
||||||
|
if (curTicks != lastCountTicks)
|
||||||
|
{
|
||||||
|
lastCountTicks = curTicks;
|
||||||
|
lastCount = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the counter by 1.
|
||||||
|
/// </summary>
|
||||||
|
public void Increment()
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = increment(ref GetCountRef(curCellCount));
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrements the counter by 1.
|
||||||
|
/// </summary>
|
||||||
|
public void Decrement()
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = decrement(ref GetCountRef(curCellCount));
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the counter by 'value'.
|
||||||
|
/// </summary>
|
||||||
|
public void Add(int value)
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = add(ref GetCountRef(curCellCount), value);
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private ref int GetCountRef(int curCellCount)
|
||||||
|
{
|
||||||
|
ref var countRef = ref count;
|
||||||
|
|
||||||
|
Cell[]? cells;
|
||||||
|
if ((cells = this.cells) != null && curCellCount > 1)
|
||||||
|
{
|
||||||
|
var cell = cells[GetIndex((uint)curCellCount)];
|
||||||
|
if (cell != null)
|
||||||
|
{
|
||||||
|
countRef = ref cell.counter.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref countRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int increment(ref int val)
|
||||||
|
{
|
||||||
|
return -val - 1 + Interlocked.Increment(ref val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int add(ref int val, int inc)
|
||||||
|
{
|
||||||
|
return -val - inc + Interlocked.Add(ref val, inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int decrement(ref int val)
|
||||||
|
{
|
||||||
|
return val - 1 - Interlocked.Decrement(ref val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryAddCell(int curCellCount)
|
||||||
|
{
|
||||||
|
if (curCellCount < s_MaxCellCount)
|
||||||
|
{
|
||||||
|
TryAddCellCore(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void TryAddCellCore(int curCellCount)
|
||||||
|
{
|
||||||
|
var cells = this.cells;
|
||||||
|
if (cells == null)
|
||||||
|
{
|
||||||
|
var newCells = new Cell[s_MaxCellCount];
|
||||||
|
cells = Interlocked.CompareExchange(ref this.cells, newCells, null) ?? newCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cells[curCellCount] == null)
|
||||||
|
{
|
||||||
|
Interlocked.CompareExchange(ref cells[curCellCount], new Cell(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cellCount == curCellCount)
|
||||||
|
{
|
||||||
|
Interlocked.CompareExchange(ref this.cellCount, curCellCount + 1, curCellCount);
|
||||||
|
//if (Interlocked.CompareExchange(ref this.cellCount, curCellCount + 1, curCellCount) == curCellCount)
|
||||||
|
//{
|
||||||
|
// System.Console.WriteLine(curCellCount + 1);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,203 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scalable 64bit counter that can be used from multiple threads.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Counter64 : CounterBase
|
||||||
|
{
|
||||||
|
private class Cell
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = CACHE_LINE * 2 - OBJ_HEADER_SIZE)]
|
||||||
|
public struct SpacedCounter
|
||||||
|
{
|
||||||
|
[FieldOffset(CACHE_LINE - OBJ_HEADER_SIZE)]
|
||||||
|
public long count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpacedCounter counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// spaced out counters
|
||||||
|
private Cell[]? cells;
|
||||||
|
|
||||||
|
// default counter
|
||||||
|
private long count;
|
||||||
|
|
||||||
|
// delayed count
|
||||||
|
private long lastCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the value of the counter at the time of the call.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The value may miss in-progress updates if the counter is being concurrently modified.
|
||||||
|
/// </remarks>
|
||||||
|
public long Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var count = this.count;
|
||||||
|
var cells = this.cells;
|
||||||
|
|
||||||
|
if (cells != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cells.Length; i++)
|
||||||
|
{
|
||||||
|
var cell = cells[i];
|
||||||
|
if (cell != null)
|
||||||
|
{
|
||||||
|
count += cell.counter.count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the approximate value of the counter at the time of the call.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// EstimatedValue could be significantly cheaper to obtain, but may be slightly delayed.
|
||||||
|
/// </remarks>
|
||||||
|
public long EstimatedValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.cellCount == 0)
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curTicks = (uint)Environment.TickCount;
|
||||||
|
// more than a millisecond passed?
|
||||||
|
if (curTicks != lastCountTicks)
|
||||||
|
{
|
||||||
|
lastCountTicks = curTicks;
|
||||||
|
lastCount = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the counter by 1.
|
||||||
|
/// </summary>
|
||||||
|
public void Increment()
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = increment(ref GetCountRef(curCellCount));
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrements the counter by 1.
|
||||||
|
/// </summary>
|
||||||
|
public void Decrement()
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = decrement(ref GetCountRef(curCellCount));
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the counter by 'value'.
|
||||||
|
/// </summary>
|
||||||
|
public void Add(int value)
|
||||||
|
{
|
||||||
|
int curCellCount = this.cellCount;
|
||||||
|
var drift = add(ref GetCountRef(curCellCount), value);
|
||||||
|
|
||||||
|
if (drift != 0)
|
||||||
|
{
|
||||||
|
TryAddCell(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private ref long GetCountRef(int curCellCount)
|
||||||
|
{
|
||||||
|
ref var countRef = ref count;
|
||||||
|
|
||||||
|
Cell[]? cells;
|
||||||
|
if ((cells = this.cells) != null && curCellCount > 1)
|
||||||
|
{
|
||||||
|
var cell = cells[GetIndex((uint)curCellCount)];
|
||||||
|
if (cell != null)
|
||||||
|
{
|
||||||
|
countRef = ref cell.counter.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref countRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long increment(ref long val)
|
||||||
|
{
|
||||||
|
return -val - 1 + Interlocked.Increment(ref val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long add(ref long val, int inc)
|
||||||
|
{
|
||||||
|
return -val - inc + Interlocked.Add(ref val, inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long decrement(ref long val)
|
||||||
|
{
|
||||||
|
return val - 1 - Interlocked.Decrement(ref val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryAddCell(int curCellCount)
|
||||||
|
{
|
||||||
|
if (curCellCount < s_MaxCellCount)
|
||||||
|
{
|
||||||
|
TryAddCellCore(curCellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryAddCellCore(int curCellCount)
|
||||||
|
{
|
||||||
|
var cells = this.cells;
|
||||||
|
if (cells == null)
|
||||||
|
{
|
||||||
|
var newCells = new Cell[s_MaxCellCount];
|
||||||
|
cells = Interlocked.CompareExchange(ref this.cells, newCells, null) ?? newCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cells[curCellCount] == null)
|
||||||
|
{
|
||||||
|
Interlocked.CompareExchange(ref cells[curCellCount], new Cell(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cellCount == curCellCount)
|
||||||
|
{
|
||||||
|
Interlocked.CompareExchange(ref this.cellCount, curCellCount + 1, curCellCount);
|
||||||
|
//if (Interlocked.CompareExchange(ref this.cellCount, curCellCount + 1, curCellCount) == curCellCount)
|
||||||
|
//{
|
||||||
|
// System.Console.WriteLine(curCellCount + 1);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Vladimir Sadov. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scalable counter base.
|
||||||
|
/// </summary>
|
||||||
|
public class CounterBase
|
||||||
|
{
|
||||||
|
private protected const int CACHE_LINE = 64;
|
||||||
|
private protected const int OBJ_HEADER_SIZE = 8;
|
||||||
|
|
||||||
|
private protected static readonly int s_MaxCellCount = Util.AlignToPowerOfTwo(Environment.ProcessorCount) + 1;
|
||||||
|
|
||||||
|
// how many cells we have
|
||||||
|
private protected int cellCount;
|
||||||
|
|
||||||
|
// delayed count time
|
||||||
|
private protected uint lastCountTicks;
|
||||||
|
|
||||||
|
private protected CounterBase()
|
||||||
|
{
|
||||||
|
// touch static
|
||||||
|
_ = s_MaxCellCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private protected unsafe static int GetIndex(uint cellCount)
|
||||||
|
{
|
||||||
|
nuint addr = (nuint)(&cellCount);
|
||||||
|
return (int)(addr % cellCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace System.Collections.Concurrent
|
||||||
|
{
|
||||||
|
internal static class Util
|
||||||
|
{
|
||||||
|
// returns 2^x >= size
|
||||||
|
internal static int AlignToPowerOfTwo(int size)
|
||||||
|
{
|
||||||
|
Debug.Assert(size > 0);
|
||||||
|
|
||||||
|
size--;
|
||||||
|
size |= size >> 1;
|
||||||
|
size |= size >> 2;
|
||||||
|
size |= size >> 4;
|
||||||
|
size |= size >> 8;
|
||||||
|
size |= size >> 16;
|
||||||
|
return size + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -44,7 +44,7 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
|
|||||||
private readonly ConcurrentQueue<Item> _free2 = new();
|
private readonly ConcurrentQueue<Item> _free2 = new();
|
||||||
|
|
||||||
/// <summary>借出去的放在这</summary>
|
/// <summary>借出去的放在这</summary>
|
||||||
private readonly ConcurrentDictionary<T, Item> _busy = new();
|
private readonly NonBlockingDictionary<T, Item> _busy = new();
|
||||||
|
|
||||||
//private readonly Object SyncRoot = new();
|
//private readonly Object SyncRoot = new();
|
||||||
#endregion
|
#endregion
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using ThingsGateway.NewLife.Threading;
|
using ThingsGateway.NewLife.Threading;
|
||||||
namespace ThingsGateway.NewLife;
|
namespace ThingsGateway.NewLife;
|
||||||
@@ -52,7 +51,7 @@ public class ExpiringDictionary<TKey, TValue> : IDisposable
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private ConcurrentDictionary<TKey, CacheItem> _dict;
|
private NonBlockingDictionary<TKey, CacheItem> _dict;
|
||||||
|
|
||||||
private readonly TimerX _cleanupTimer;
|
private readonly TimerX _cleanupTimer;
|
||||||
private int defaultExpire = 60;
|
private int defaultExpire = 60;
|
||||||
@@ -61,7 +60,7 @@ public class ExpiringDictionary<TKey, TValue> : IDisposable
|
|||||||
{
|
{
|
||||||
defaultExpire = expire;
|
defaultExpire = expire;
|
||||||
this.comparer = comparer;
|
this.comparer = comparer;
|
||||||
_dict = new ConcurrentDictionary<TKey, CacheItem>(comparer);
|
_dict = new NonBlockingDictionary<TKey, CacheItem>(comparer);
|
||||||
|
|
||||||
_cleanupTimer = new TimerX(TimerClear, null, 10000, 10000) { Async = true };
|
_cleanupTimer = new TimerX(TimerClear, null, 10000, 10000) { Async = true };
|
||||||
}
|
}
|
||||||
|
@@ -13,8 +13,8 @@ public class FastMapperOption
|
|||||||
public static class FastMapper
|
public static class FastMapper
|
||||||
{
|
{
|
||||||
// 泛型 + 非泛型共用缓存
|
// 泛型 + 非泛型共用缓存
|
||||||
private static readonly ConcurrentDictionary<(Type Source, Type Target), Delegate> _mapCache
|
private static readonly NonBlockingDictionary<(Type Source, Type Target), Delegate> _mapCache
|
||||||
= new ConcurrentDictionary<(Type, Type), Delegate>();
|
= new NonBlockingDictionary<(Type, Type), Delegate>();
|
||||||
|
|
||||||
#region 泛型入口
|
#region 泛型入口
|
||||||
public static TTarget Mapper<TSource, TTarget>(TSource source, FastMapperOption option = null)
|
public static TTarget Mapper<TSource, TTarget>(TSource source, FastMapperOption option = null)
|
||||||
|
@@ -168,8 +168,8 @@ public class CompositeConfigProvider : IConfigProvider
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 绑定
|
#region 绑定
|
||||||
private readonly ConcurrentDictionary<Object, String> _models = [];
|
private readonly NonBlockingDictionary<Object, String> _models = [];
|
||||||
private readonly ConcurrentDictionary<Object, ModelWrap> _models2 = [];
|
private readonly NonBlockingDictionary<Object, ModelWrap> _models2 = [];
|
||||||
/// <summary>绑定模型,使能热更新,配置存储数据改变时同步修改模型属性</summary>
|
/// <summary>绑定模型,使能热更新,配置存储数据改变时同步修改模型属性</summary>
|
||||||
/// <typeparam name="T">模型。可通过实现IConfigMapping接口来自定义映射配置到模型实例</typeparam>
|
/// <typeparam name="T">模型。可通过实现IConfigMapping接口来自定义映射配置到模型实例</typeparam>
|
||||||
/// <param name="model">模型实例</param>
|
/// <param name="model">模型实例</param>
|
||||||
|
@@ -11,7 +11,7 @@ public static class DictionaryExtensions
|
|||||||
/// <param name="dict"></param>
|
/// <param name="dict"></param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Boolean Remove<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key) where TKey : notnull => dict.TryRemove(key, out _);
|
public static Boolean Remove<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dict, TKey key) where TKey : notnull => dict.TryRemove(key, out _);
|
||||||
|
|
||||||
#if !NET6_0_OR_GREATER
|
#if !NET6_0_OR_GREATER
|
||||||
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> pairs, TKey key, TValue value)
|
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> pairs, TKey key, TValue value)
|
||||||
@@ -77,7 +77,7 @@ public static class DictionaryExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量出队
|
/// 批量出队
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<T> ToListWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
|
public static List<T> ToListWithDequeue<TKEY, T>(this NonBlockingDictionary<TKEY, T> values, int maxCount = 0)
|
||||||
{
|
{
|
||||||
if (maxCount <= 0)
|
if (maxCount <= 0)
|
||||||
{
|
{
|
||||||
@@ -105,7 +105,7 @@ public static class DictionaryExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量出队
|
/// 批量出队
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Dictionary<TKEY, T> ToDictWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
|
public static Dictionary<TKEY, T> ToDictWithDequeue<TKEY, T>(this NonBlockingDictionary<TKEY, T> values, int maxCount = 0)
|
||||||
{
|
{
|
||||||
if (maxCount <= 0)
|
if (maxCount <= 0)
|
||||||
{
|
{
|
||||||
@@ -135,7 +135,7 @@ public static class DictionaryExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量出队
|
/// 批量出队
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<KeyValuePair<TKEY, T>> ToIEnumerableKVWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
|
public static IEnumerable<KeyValuePair<TKEY, T>> ToIEnumerableKVWithDequeue<TKEY, T>(this NonBlockingDictionary<TKEY, T> values, int maxCount = 0)
|
||||||
{
|
{
|
||||||
if (values.IsEmpty) yield break;
|
if (values.IsEmpty) yield break;
|
||||||
|
|
||||||
|
@@ -101,7 +101,7 @@ public static class LinqExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从并发字典中删除
|
/// 从并发字典中删除
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool Remove<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key) where TKey : notnull
|
public static bool Remove<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dict, TKey key) where TKey : notnull
|
||||||
{
|
{
|
||||||
return dict.TryRemove(key, out TValue? _);
|
return dict.TryRemove(key, out TValue? _);
|
||||||
}
|
}
|
||||||
|
@@ -97,7 +97,7 @@ public class ConsoleLog : Logger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly ConcurrentDictionary<Int32, ConsoleColor> dic = new();
|
static readonly NonBlockingDictionary<Int32, ConsoleColor> dic = new();
|
||||||
static readonly ConsoleColor[] colors = [
|
static readonly ConsoleColor[] colors = [
|
||||||
ConsoleColor.Green, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.White, ConsoleColor.Yellow,
|
ConsoleColor.Green, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.White, ConsoleColor.Yellow,
|
||||||
ConsoleColor.DarkGreen, ConsoleColor.DarkCyan, ConsoleColor.DarkMagenta, ConsoleColor.DarkRed, ConsoleColor.DarkYellow ];
|
ConsoleColor.DarkGreen, ConsoleColor.DarkCyan, ConsoleColor.DarkMagenta, ConsoleColor.DarkRed, ConsoleColor.DarkYellow ];
|
||||||
|
@@ -109,7 +109,7 @@ public class DefaultTracer : DisposeBase, ITracer, ILogFeature
|
|||||||
public IPool<ISpan> SpanPool => _SpanPool ??= new MySpanPool();
|
public IPool<ISpan> SpanPool => _SpanPool ??= new MySpanPool();
|
||||||
|
|
||||||
/// <summary>Span构建器集合</summary>
|
/// <summary>Span构建器集合</summary>
|
||||||
protected ConcurrentDictionary<String, ISpanBuilder> _builders = new();
|
protected NonBlockingDictionary<String, ISpanBuilder> _builders = new();
|
||||||
|
|
||||||
/// <summary>采样定时器</summary>
|
/// <summary>采样定时器</summary>
|
||||||
protected TimerX? _timer;
|
protected TimerX? _timer;
|
||||||
@@ -292,7 +292,7 @@ public class DefaultTracer : DisposeBase, ITracer, ILogFeature
|
|||||||
var bs = _builders;
|
var bs = _builders;
|
||||||
if (bs.IsEmpty) return [];
|
if (bs.IsEmpty) return [];
|
||||||
|
|
||||||
_builders = new ConcurrentDictionary<String, ISpanBuilder>();
|
_builders = new NonBlockingDictionary<String, ISpanBuilder>();
|
||||||
|
|
||||||
var bs2 = bs.Values.Where(e => e.Total > 0).ToArray();
|
var bs2 = bs.Values.Where(e => e.Total > 0).ToArray();
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ public class TextFileLog : Logger, IDisposable
|
|||||||
_Timer = new TimerX(DoWriteAndClose, null, 0_000, 5_000) { Async = true };
|
_Timer = new TimerX(DoWriteAndClose, null, 0_000, 5_000) { Async = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<String, TextFileLog> cache = new(StringComparer.OrdinalIgnoreCase);
|
private static readonly NonBlockingDictionary<String, TextFileLog> cache = new(StringComparer.OrdinalIgnoreCase);
|
||||||
/// <summary>每个目录的日志实例应该只有一个,所以采用静态创建</summary>
|
/// <summary>每个目录的日志实例应该只有一个,所以采用静态创建</summary>
|
||||||
/// <param name="path">日志目录或日志文件路径</param>
|
/// <param name="path">日志目录或日志文件路径</param>
|
||||||
/// <param name="fileFormat"></param>
|
/// <param name="fileFormat"></param>
|
||||||
@@ -257,7 +257,7 @@ public class TextFileLog : Logger, IDisposable
|
|||||||
{
|
{
|
||||||
// 删除最旧的文件
|
// 删除最旧的文件
|
||||||
var retain = fis.Length - Backups;
|
var retain = fis.Length - Backups;
|
||||||
fis = fis.OrderBy(e => e.CreationTime).Take(retain).ToArray();
|
fis = fis.OrderBy(e => e.LastWriteTimeUtc).Take(retain).ToArray();
|
||||||
foreach (var item in fis)
|
foreach (var item in fis)
|
||||||
{
|
{
|
||||||
OnWrite(LogLevel.Info, "The log file has reached the maximum limit of {0}, delete {1}, size {2: n0} Byte", Backups, item.Name, item.Length);
|
OnWrite(LogLevel.Info, "The log file has reached the maximum limit of {0}, delete {1}, size {2: n0} Byte", Backups, item.Name, item.Length);
|
||||||
|
@@ -59,7 +59,7 @@ public interface IEventHandler<TEvent>
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class EventBus<TEvent> : DisposeBase, IEventBus<TEvent>
|
public class EventBus<TEvent> : DisposeBase, IEventBus<TEvent>
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<String, IEventHandler<TEvent>> _handlers = [];
|
private readonly NonBlockingDictionary<String, IEventHandler<TEvent>> _handlers = [];
|
||||||
/// <summary>已订阅的事件处理器集合</summary>
|
/// <summary>已订阅的事件处理器集合</summary>
|
||||||
public IDictionary<String, IEventHandler<TEvent>> Handlers => _handlers;
|
public IDictionary<String, IEventHandler<TEvent>> Handlers => _handlers;
|
||||||
|
|
||||||
|
@@ -20,9 +20,9 @@ public class DeferredQueue : DisposeBase
|
|||||||
/// <summary>名称</summary>
|
/// <summary>名称</summary>
|
||||||
public String Name { get; set; }
|
public String Name { get; set; }
|
||||||
|
|
||||||
private volatile ConcurrentDictionary<String, Object> _Entities = new();
|
private volatile NonBlockingDictionary<String, Object> _Entities = new();
|
||||||
/// <summary>实体字典</summary>
|
/// <summary>实体字典</summary>
|
||||||
public ConcurrentDictionary<String, Object> Entities => _Entities;
|
public NonBlockingDictionary<String, Object> Entities => _Entities;
|
||||||
|
|
||||||
/// <summary>跟踪数。达到该值时输出跟踪日志,默认1000</summary>
|
/// <summary>跟踪数。达到该值时输出跟踪日志,默认1000</summary>
|
||||||
public Int32 TraceCount { get; set; } = 1000;
|
public Int32 TraceCount { get; set; } = 1000;
|
||||||
@@ -206,7 +206,7 @@ public class DeferredQueue : DisposeBase
|
|||||||
var es = _Entities;
|
var es = _Entities;
|
||||||
if (es.IsEmpty) return;
|
if (es.IsEmpty) return;
|
||||||
|
|
||||||
_Entities = new ConcurrentDictionary<String, Object>();
|
_Entities = new NonBlockingDictionary<String, Object>();
|
||||||
var times = _Times;
|
var times = _Times;
|
||||||
|
|
||||||
Interlocked.Add(ref _count, -es.Count);
|
Interlocked.Add(ref _count, -es.Count);
|
||||||
|
@@ -18,7 +18,7 @@ class MyServiceScope : IServiceScope, IServiceProvider
|
|||||||
|
|
||||||
public IServiceProvider ServiceProvider => this;
|
public IServiceProvider ServiceProvider => this;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Type, Object?> _cache = new();
|
private readonly NonBlockingDictionary<Type, Object?> _cache = new();
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,7 @@ public class DnsResolver : IDnsResolver
|
|||||||
/// <summary>缓存超时时间</summary>
|
/// <summary>缓存超时时间</summary>
|
||||||
public TimeSpan Expire { set; get; } = TimeSpan.FromMinutes(5);
|
public TimeSpan Expire { set; get; } = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<String, DnsItem> _cache = new();
|
private readonly NonBlockingDictionary<String, DnsItem> _cache = new();
|
||||||
|
|
||||||
/// <summary>解析域名</summary>
|
/// <summary>解析域名</summary>
|
||||||
/// <param name="host"></param>
|
/// <param name="host"></param>
|
||||||
|
@@ -146,7 +146,7 @@ public class NetServer : DisposeBase, IServer, IExtend, ILogFeature
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public IServiceProvider? ServiceProvider { get; set; }
|
public IServiceProvider? ServiceProvider { get; set; }
|
||||||
|
|
||||||
private ConcurrentDictionary<String, Object?>? _items;
|
private NonBlockingDictionary<String, Object?>? _items;
|
||||||
/// <summary>数据项</summary>
|
/// <summary>数据项</summary>
|
||||||
public IDictionary<String, Object?> Items => _items ??= new();
|
public IDictionary<String, Object?> Items => _items ??= new();
|
||||||
|
|
||||||
@@ -486,7 +486,7 @@ public class NetServer : DisposeBase, IServer, IExtend, ILogFeature
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 会话
|
#region 会话
|
||||||
private readonly ConcurrentDictionary<Int32, INetSession> _Sessions = new();
|
private readonly NonBlockingDictionary<Int32, INetSession> _Sessions = new();
|
||||||
/// <summary>会话集合。用自增的数字ID作为标识,业务应用自己维持ID与业务主键的对应关系。</summary>
|
/// <summary>会话集合。用自增的数字ID作为标识,业务应用自己维持ID与业务主键的对应关系。</summary>
|
||||||
public IDictionary<Int32, INetSession> Sessions => _Sessions;
|
public IDictionary<Int32, INetSession> Sessions => _Sessions;
|
||||||
|
|
||||||
|
@@ -853,7 +853,7 @@ public abstract class SessionBase : DisposeBase, ISocketClient, ITransport, ILog
|
|||||||
#endregion 异常处理
|
#endregion 异常处理
|
||||||
|
|
||||||
#region 扩展接口
|
#region 扩展接口
|
||||||
private ConcurrentDictionary<String, Object?>? _items;
|
private NonBlockingDictionary<String, Object?>? _items;
|
||||||
/// <summary>数据项</summary>
|
/// <summary>数据项</summary>
|
||||||
public IDictionary<String, Object?> Items => _items ??= new();
|
public IDictionary<String, Object?> Items => _items ??= new();
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ namespace ThingsGateway.NewLife.Net;
|
|||||||
internal class SessionCollection : DisposeBase, IDictionary<String, ISocketSession>
|
internal class SessionCollection : DisposeBase, IDictionary<String, ISocketSession>
|
||||||
{
|
{
|
||||||
#region 属性
|
#region 属性
|
||||||
private readonly ConcurrentDictionary<String, ISocketSession> _dic = new();
|
private readonly NonBlockingDictionary<String, ISocketSession> _dic = new();
|
||||||
|
|
||||||
/// <summary>服务端</summary>
|
/// <summary>服务端</summary>
|
||||||
public ISocketServer Server { get; private set; }
|
public ISocketServer Server { get; private set; }
|
||||||
|
@@ -400,7 +400,7 @@ public class UdpSession : DisposeBase, ISocketSession, ITransport, ILogFeature
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 扩展接口
|
#region 扩展接口
|
||||||
private ConcurrentDictionary<String, Object?>? _items;
|
private NonBlockingDictionary<String, Object?>? _items;
|
||||||
/// <summary>数据项</summary>
|
/// <summary>数据项</summary>
|
||||||
public IDictionary<String, Object?> Items => _items ??= new();
|
public IDictionary<String, Object?> Items => _items ??= new();
|
||||||
|
|
||||||
|
@@ -212,7 +212,7 @@ public class FullRedis : Redis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentDictionary<String, IPool<RedisClient>> _pools = new();
|
private NonBlockingDictionary<String, IPool<RedisClient>> _pools = new();
|
||||||
/// <summary>获取指定节点的连接池</summary>
|
/// <summary>获取指定节点的连接池</summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
@@ -1106,10 +1106,10 @@ public class RedisClient : DisposeBase
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 辅助
|
#region 辅助
|
||||||
private static readonly ConcurrentDictionary<String, String> _cache0 = new();
|
private static readonly NonBlockingDictionary<String, String> _cache0 = new();
|
||||||
private static readonly ConcurrentDictionary<String, String> _cache1 = new();
|
private static readonly NonBlockingDictionary<String, String> _cache1 = new();
|
||||||
private static readonly ConcurrentDictionary<String, String> _cache2 = new();
|
private static readonly NonBlockingDictionary<String, String> _cache2 = new();
|
||||||
private static readonly ConcurrentDictionary<String, String> _cache3 = new();
|
private static readonly NonBlockingDictionary<String, String> _cache3 = new();
|
||||||
/// <summary>获取命令对应的字节数组,全局缓存</summary>
|
/// <summary>获取命令对应的字节数组,全局缓存</summary>
|
||||||
/// <param name="cmd"></param>
|
/// <param name="cmd"></param>
|
||||||
/// <param name="args"></param>
|
/// <param name="args"></param>
|
||||||
|
@@ -94,7 +94,7 @@ public class AssemblyX
|
|||||||
#region 构造
|
#region 构造
|
||||||
private AssemblyX(Assembly asm) => Asm = asm;
|
private AssemblyX(Assembly asm) => Asm = asm;
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Assembly, AssemblyX> cache = new();
|
private static readonly NonBlockingDictionary<Assembly, AssemblyX> cache = new();
|
||||||
/// <summary>创建程序集辅助对象</summary>
|
/// <summary>创建程序集辅助对象</summary>
|
||||||
/// <param name="asm"></param>
|
/// <param name="asm"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -234,7 +234,7 @@ public class AssemblyX
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 方法
|
#region 方法
|
||||||
private readonly ConcurrentDictionary<String, Type?> typeCache2 = new();
|
private readonly NonBlockingDictionary<String, Type?> typeCache2 = new();
|
||||||
/// <summary>从程序集中查找指定名称的类型</summary>
|
/// <summary>从程序集中查找指定名称的类型</summary>
|
||||||
/// <param name="typeName"></param>
|
/// <param name="typeName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -268,7 +268,7 @@ public class AssemblyX
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 插件
|
#region 插件
|
||||||
private readonly ConcurrentDictionary<Type, List<Type>> _plugins = new();
|
private readonly NonBlockingDictionary<Type, List<Type>> _plugins = new();
|
||||||
/// <summary>查找插件,带缓存</summary>
|
/// <summary>查找插件,带缓存</summary>
|
||||||
/// <param name="baseType">类型</param>
|
/// <param name="baseType">类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
@@ -10,7 +10,7 @@ namespace ThingsGateway.NewLife;
|
|||||||
public static class AttributeX
|
public static class AttributeX
|
||||||
{
|
{
|
||||||
#region 静态方法
|
#region 静态方法
|
||||||
private static readonly ConcurrentDictionary<String, Object> _asmCache = new();
|
private static readonly NonBlockingDictionary<String, Object> _asmCache = new();
|
||||||
|
|
||||||
/// <summary>获取自定义属性,带有缓存功能,避免因.Net内部GetCustomAttributes没有缓存而带来的损耗</summary>
|
/// <summary>获取自定义属性,带有缓存功能,避免因.Net内部GetCustomAttributes没有缓存而带来的损耗</summary>
|
||||||
/// <typeparam name="TAttribute"></typeparam>
|
/// <typeparam name="TAttribute"></typeparam>
|
||||||
|
@@ -317,8 +317,8 @@ public class DefaultReflect : IReflect
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 反射获取 字段/属性
|
#region 反射获取 字段/属性
|
||||||
private readonly ConcurrentDictionary<Type, IList<FieldInfo>> _cache1 = new();
|
private readonly NonBlockingDictionary<Type, IList<FieldInfo>> _cache1 = new();
|
||||||
private readonly ConcurrentDictionary<Type, IList<FieldInfo>> _cache2 = new();
|
private readonly NonBlockingDictionary<Type, IList<FieldInfo>> _cache2 = new();
|
||||||
/// <summary>获取字段</summary>
|
/// <summary>获取字段</summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="baseFirst"></param>
|
/// <param name="baseFirst"></param>
|
||||||
@@ -353,8 +353,8 @@ public class DefaultReflect : IReflect
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Type, IList<PropertyInfo>> _cache3 = new();
|
private readonly NonBlockingDictionary<Type, IList<PropertyInfo>> _cache3 = new();
|
||||||
private readonly ConcurrentDictionary<Type, IList<PropertyInfo>> _cache4 = new();
|
private readonly NonBlockingDictionary<Type, IList<PropertyInfo>> _cache4 = new();
|
||||||
/// <summary>获取属性</summary>
|
/// <summary>获取属性</summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="baseFirst"></param>
|
/// <param name="baseFirst"></param>
|
||||||
@@ -805,7 +805,7 @@ public class DefaultReflect : IReflect
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 插件
|
#region 插件
|
||||||
//private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Boolean>> _as_cache = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Boolean>>();
|
//private readonly NonBlockingDictionary<Type, NonBlockingDictionary<Type, Boolean>> _as_cache = new NonBlockingDictionary<Type, NonBlockingDictionary<Type, Boolean>>();
|
||||||
/// <summary>是否子类</summary>
|
/// <summary>是否子类</summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="baseType"></param>
|
/// <param name="baseType"></param>
|
||||||
@@ -832,7 +832,7 @@ public class DefaultReflect : IReflect
|
|||||||
//var key = $"{type.FullName}_{baseType.FullName}";
|
//var key = $"{type.FullName}_{baseType.FullName}";
|
||||||
//if (!_as_cache.TryGetValue(type, out var dic))
|
//if (!_as_cache.TryGetValue(type, out var dic))
|
||||||
//{
|
//{
|
||||||
// dic = new ConcurrentDictionary<Type, Boolean>();
|
// dic = new NonBlockingDictionary<Type, Boolean>();
|
||||||
// _as_cache.TryAdd(type, dic);
|
// _as_cache.TryAdd(type, dic);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
@@ -111,7 +111,7 @@ public class ScriptEngine
|
|||||||
IsExpression = isExpression;
|
IsExpression = isExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly ConcurrentDictionary<String, ScriptEngine> _cache = new(StringComparer.OrdinalIgnoreCase);
|
static readonly NonBlockingDictionary<String, ScriptEngine> _cache = new(StringComparer.OrdinalIgnoreCase);
|
||||||
/// <summary>为指定代码片段创建脚本引擎实例。采用缓存,避免同一脚本重复创建引擎。</summary>
|
/// <summary>为指定代码片段创建脚本引擎实例。采用缓存,避免同一脚本重复创建引擎。</summary>
|
||||||
/// <param name="code">代码片段</param>
|
/// <param name="code">代码片段</param>
|
||||||
/// <param name="isExpression">是否表达式,表达式将编译成为一个Main方法</param>
|
/// <param name="isExpression">是否表达式,表达式将编译成为一个Main方法</param>
|
||||||
|
@@ -243,7 +243,7 @@ public class BinaryComposite : BinaryHandlerBase
|
|||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<MemberInfo, IMemberAccessor?> _cache = new();
|
private static readonly NonBlockingDictionary<MemberInfo, IMemberAccessor?> _cache = new();
|
||||||
private static Boolean TryGetAccessor(MemberInfo member, [NotNullWhen(true)] out IMemberAccessor? acc)
|
private static Boolean TryGetAccessor(MemberInfo member, [NotNullWhen(true)] out IMemberAccessor? acc)
|
||||||
{
|
{
|
||||||
if (_cache.TryGetValue(member, out acc)) return acc != null;
|
if (_cache.TryGetValue(member, out acc)) return acc != null;
|
||||||
|
@@ -323,7 +323,7 @@ public class SystemJson : IJsonHost
|
|||||||
|
|
||||||
#region IJsonHost 成员
|
#region IJsonHost 成员
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, JsonSerializerOptions> _optionsCache = new();
|
private static readonly NonBlockingDictionary<string, JsonSerializerOptions> _optionsCache = new();
|
||||||
|
|
||||||
private static JsonSerializerOptions GetOptions(JsonSerializerOptions jsonSerializerOptions, bool indented, bool nullValue, bool camelCase)
|
private static JsonSerializerOptions GetOptions(JsonSerializerOptions jsonSerializerOptions, bool indented, bool nullValue, bool camelCase)
|
||||||
{
|
{
|
||||||
|
@@ -11,7 +11,7 @@ namespace ThingsGateway.NewLife.Serialization;
|
|||||||
/// <summary>序列化助手</summary>
|
/// <summary>序列化助手</summary>
|
||||||
public static class SerialHelper
|
public static class SerialHelper
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<PropertyInfo, String> _cache = new();
|
private static readonly NonBlockingDictionary<PropertyInfo, String> _cache = new();
|
||||||
/// <summary>获取序列化名称</summary>
|
/// <summary>获取序列化名称</summary>
|
||||||
/// <param name="pi"></param>
|
/// <param name="pi"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
@@ -31,7 +31,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Type, SugarColumn> _typeInfoCache = new();
|
private static readonly NonBlockingDictionary<Type, SugarColumn> _typeInfoCache = new();
|
||||||
|
|
||||||
static SerializeService()
|
static SerializeService()
|
||||||
{
|
{
|
||||||
|
@@ -4,7 +4,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
{
|
{
|
||||||
public static class CallContextAsync<T>
|
public static class CallContextAsync<T>
|
||||||
{
|
{
|
||||||
static ConcurrentDictionary<string, AsyncLocal<T>> state = new ConcurrentDictionary<string, AsyncLocal<T>>();
|
static NonBlockingDictionary<string, AsyncLocal<T>> state = new NonBlockingDictionary<string, AsyncLocal<T>>();
|
||||||
public static void SetData(string name, T data) =>
|
public static void SetData(string name, T data) =>
|
||||||
state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data;
|
state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data;
|
||||||
public static T GetData(string name) =>
|
public static T GetData(string name) =>
|
||||||
@@ -13,7 +13,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
|
|
||||||
public static class CallContextThread<T>
|
public static class CallContextThread<T>
|
||||||
{
|
{
|
||||||
static ConcurrentDictionary<string, ThreadLocal<T>> state = new ConcurrentDictionary<string, ThreadLocal<T>>();
|
static NonBlockingDictionary<string, ThreadLocal<T>> state = new NonBlockingDictionary<string, ThreadLocal<T>>();
|
||||||
public static void SetData(string name, T data) =>
|
public static void SetData(string name, T data) =>
|
||||||
state.GetOrAdd(name, _ => new ThreadLocal<T>()).Value = data;
|
state.GetOrAdd(name, _ => new ThreadLocal<T>()).Value = data;
|
||||||
public static T GetData(string name) =>
|
public static T GetData(string name) =>
|
||||||
|
@@ -8,7 +8,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
{
|
{
|
||||||
internal static class FastCopy
|
internal static class FastCopy
|
||||||
{
|
{
|
||||||
static ConcurrentDictionary<string, object> copiers = new ConcurrentDictionary<string, object>();
|
static NonBlockingDictionary<string, object> copiers = new NonBlockingDictionary<string, object>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 复制两个对象同名属性值
|
/// 复制两个对象同名属性值
|
||||||
|
@@ -22,8 +22,8 @@ namespace ThingsGateway.SqlSugar
|
|||||||
}
|
}
|
||||||
public static class PropertyCallAdapterProvider<TThis>
|
public static class PropertyCallAdapterProvider<TThis>
|
||||||
{
|
{
|
||||||
private static readonly System.Collections.Concurrent.ConcurrentDictionary<string, IPropertyCallAdapter<TThis>> _instances =
|
private static readonly System.Collections.Concurrent.NonBlockingDictionary<string, IPropertyCallAdapter<TThis>> _instances =
|
||||||
new System.Collections.Concurrent.ConcurrentDictionary<string, IPropertyCallAdapter<TThis>>();
|
new System.Collections.Concurrent.NonBlockingDictionary<string, IPropertyCallAdapter<TThis>>();
|
||||||
|
|
||||||
public static IPropertyCallAdapter<TThis> GetInstance(string forPropertyName)
|
public static IPropertyCallAdapter<TThis> GetInstance(string forPropertyName)
|
||||||
{
|
{
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PluginVersion>10.11.105</PluginVersion>
|
<PluginVersion>10.11.107</PluginVersion>
|
||||||
<ProPluginVersion>10.11.105</ProPluginVersion>
|
<ProPluginVersion>10.11.107</ProPluginVersion>
|
||||||
<DefaultVersion>10.11.105</DefaultVersion>
|
<DefaultVersion>10.11.107</DefaultVersion>
|
||||||
<AuthenticationVersion>10.11.6</AuthenticationVersion>
|
<AuthenticationVersion>10.11.6</AuthenticationVersion>
|
||||||
<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
|
<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
|
||||||
<NET8Version>8.0.21</NET8Version>
|
<NET8Version>8.0.21</NET8Version>
|
||||||
|
@@ -64,7 +64,7 @@ public class DDPUdpSessionChannel : UdpSessionChannel, IClientChannel, IDtuUdpSe
|
|||||||
|
|
||||||
public EndPoint DefaultEndpoint => RemoteIPHost?.EndPoint;
|
public EndPoint DefaultEndpoint => RemoteIPHost?.EndPoint;
|
||||||
|
|
||||||
ConcurrentDictionary<string, WaitLock> WaitLocks { get; } = new();
|
NonBlockingDictionary<string, WaitLock> WaitLocks { get; } = new();
|
||||||
|
|
||||||
public override WaitLock GetLock(string key)
|
public override WaitLock GetLock(string key)
|
||||||
{
|
{
|
||||||
|
@@ -19,7 +19,7 @@ namespace ThingsGateway.Foundation;
|
|||||||
[DebuggerDisplay("Count={Count}")]
|
[DebuggerDisplay("Count={Count}")]
|
||||||
internal class InternalConcurrentDictionary<TKey, TValue> : IEnumerable<TValue>
|
internal class InternalConcurrentDictionary<TKey, TValue> : IEnumerable<TValue>
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<TKey, TValue> m_clients = new();
|
private readonly NonBlockingDictionary<TKey, TValue> m_clients = new();
|
||||||
|
|
||||||
public int Count => m_clients.Count;
|
public int Count => m_clients.Count;
|
||||||
|
|
||||||
|
@@ -81,8 +81,8 @@ public class DeviceSingleStreamDataHandleAdapter<TRequest> : CustomDataHandlingA
|
|||||||
request = Request == null ? Request = GetInstance() : Request;
|
request = Request == null ? Request = GetInstance() : Request;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!beCached)
|
//if (!beCached)
|
||||||
request = GetInstance();
|
request = GetInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pos = byteBlock.BytesRead;
|
var pos = byteBlock.BytesRead;
|
||||||
|
@@ -583,8 +583,16 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var operResult = waitData.Check(reusableTimeout.TimeoutStatus);
|
var operResult = waitData.Check(reusableTimeout.TimeoutStatus);
|
||||||
waitData.CompletedData.ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}";
|
if(waitData.CompletedData!=null)
|
||||||
return waitData.CompletedData;
|
{
|
||||||
|
waitData.CompletedData.ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}";
|
||||||
|
return waitData.CompletedData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new MessageBase(new OperationCanceledException());
|
||||||
|
}
|
||||||
|
|
||||||
//return new MessageBase(operResult) { ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}" };
|
//return new MessageBase(operResult) { ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ namespace ThingsGateway.Foundation;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class JsonLocalizer : IStringLocalizer
|
public class JsonLocalizer : IStringLocalizer
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, JObject> _resources = new();
|
private readonly NonBlockingDictionary<string, JObject> _resources = new();
|
||||||
private string _folderName;
|
private string _folderName;
|
||||||
private Type _type;
|
private Type _type;
|
||||||
|
|
||||||
|
@@ -533,7 +533,7 @@ public abstract partial class CollectBase : DriverBase
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
protected async Task Check(Dictionary<VariableRuntime, JToken> writeInfoLists, ConcurrentDictionary<string, OperResult> operResults, CancellationToken cancellationToken)
|
protected async Task Check(Dictionary<VariableRuntime, JToken> writeInfoLists, NonBlockingDictionary<string, OperResult> operResults, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (VariableSourceReadsEnable)
|
if (VariableSourceReadsEnable)
|
||||||
{
|
{
|
||||||
@@ -604,7 +604,7 @@ public abstract partial class CollectBase : DriverBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcurrentDictionary<string, OperResult<object>> operResults = new();
|
NonBlockingDictionary<string, OperResult<object>> operResults = new();
|
||||||
|
|
||||||
|
|
||||||
using var writeLock = await ReadWriteLock.WriterLockAsync(cancellationToken).ConfigureAwait(false);
|
using var writeLock = await ReadWriteLock.WriterLockAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
@@ -199,7 +199,7 @@ public abstract class CollectFoundationBase : CollectBase
|
|||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
|
||||||
// 创建用于存储操作结果的并发字典
|
// 创建用于存储操作结果的并发字典
|
||||||
ConcurrentDictionary<string, OperResult> operResults = new();
|
NonBlockingDictionary<string, OperResult> operResults = new();
|
||||||
// 使用并发方式遍历写入信息列表,并进行异步写入操作
|
// 使用并发方式遍历写入信息列表,并进行异步写入操作
|
||||||
await writeInfoLists.ParallelForEachAsync(async (writeInfo, cancellationToken) =>
|
await writeInfoLists.ParallelForEachAsync(async (writeInfo, cancellationToken) =>
|
||||||
{
|
{
|
||||||
|
@@ -93,7 +93,7 @@ public class Variable : BaseDataEntity, IValidatableObject
|
|||||||
[System.Text.Json.Serialization.JsonIgnore]
|
[System.Text.Json.Serialization.JsonIgnore]
|
||||||
[Newtonsoft.Json.JsonIgnore]
|
[Newtonsoft.Json.JsonIgnore]
|
||||||
[MapperIgnore]
|
[MapperIgnore]
|
||||||
public ConcurrentDictionary<long, ModelValueValidateForm>? VariablePropertyModels;
|
public NonBlockingDictionary<long, ModelValueValidateForm>? VariablePropertyModels;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设备
|
/// 设备
|
||||||
|
@@ -524,11 +524,11 @@ public static class GlobalData
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的通道字典,用于存储通道对象
|
/// 内部使用的通道字典,用于存储通道对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<long, ChannelRuntime> IdChannels { get; } = new();
|
internal static NonBlockingDictionary<long, ChannelRuntime> IdChannels { get; } = new();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的通道字典,用于存储通道对象
|
/// 内部使用的通道字典,用于存储通道对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, ChannelRuntime> Channels { get; } = new();
|
internal static NonBlockingDictionary<string, ChannelRuntime> Channels { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 只读的设备字典,提供对设备的只读访问
|
/// 只读的设备字典,提供对设备的只读访问
|
||||||
@@ -543,28 +543,28 @@ public static class GlobalData
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的设备字典,用于存储设备对象
|
/// 内部使用的设备字典,用于存储设备对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<string, DeviceRuntime> Devices { get; } = new();
|
internal static NonBlockingDictionary<string, DeviceRuntime> Devices { get; } = new();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的设备字典,用于存储设备对象
|
/// 内部使用的设备字典,用于存储设备对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<long, DeviceRuntime> IdDevices { get; } = new();
|
internal static NonBlockingDictionary<long, DeviceRuntime> IdDevices { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的报警配置变量字典
|
/// 内部使用的报警配置变量字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<long, VariableRuntime> AlarmEnableIdVariables { get; } = new();
|
internal static NonBlockingDictionary<long, VariableRuntime> AlarmEnableIdVariables { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的报警配置变量字典
|
/// 内部使用的报警配置变量字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<long, AlarmVariable> RealAlarmIdVariables { get; } = new();
|
internal static NonBlockingDictionary<long, AlarmVariable> RealAlarmIdVariables { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部使用的变量字典,用于存储变量对象
|
/// 内部使用的变量字典,用于存储变量对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConcurrentDictionary<long, VariableRuntime> IdVariables { get; } = new();
|
internal static NonBlockingDictionary<long, VariableRuntime> IdVariables { get; } = new();
|
||||||
|
|
||||||
internal static ConcurrentDictionary<string, VariableRuntime> MemoryVariables { get; } = new();
|
internal static NonBlockingDictionary<string, VariableRuntime> MemoryVariables { get; } = new();
|
||||||
public static IReadOnlyDictionary<string, VariableRuntime> ReadOnlyMemoryVariables => MemoryVariables;
|
public static IReadOnlyDictionary<string, VariableRuntime> ReadOnlyMemoryVariables => MemoryVariables;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -84,7 +84,7 @@ public class ChannelRuntime : Channel
|
|||||||
[Newtonsoft.Json.JsonIgnore]
|
[Newtonsoft.Json.JsonIgnore]
|
||||||
[MapperIgnore]
|
[MapperIgnore]
|
||||||
[AutoGenerateColumn(Ignore = true)]
|
[AutoGenerateColumn(Ignore = true)]
|
||||||
internal ConcurrentDictionary<long, DeviceRuntime>? DeviceRuntimes { get; } = new();
|
internal NonBlockingDictionary<long, DeviceRuntime>? DeviceRuntimes { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设备数量
|
/// 设备数量
|
||||||
|
@@ -251,7 +251,7 @@ public class DeviceRuntime : Device
|
|||||||
[Newtonsoft.Json.JsonIgnore]
|
[Newtonsoft.Json.JsonIgnore]
|
||||||
[MapperIgnore]
|
[MapperIgnore]
|
||||||
[AutoGenerateColumn(Ignore = true)]
|
[AutoGenerateColumn(Ignore = true)]
|
||||||
internal ConcurrentDictionary<string, VariableRuntime>? VariableRuntimes { get; } = new();
|
internal NonBlockingDictionary<string, VariableRuntime>? VariableRuntimes { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 特殊方法变量
|
/// 特殊方法变量
|
||||||
|
@@ -439,7 +439,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
|||||||
|
|
||||||
// 获取所有驱动程序,并将驱动程序名称作为键构建字典
|
// 获取所有驱动程序,并将驱动程序名称作为键构建字典
|
||||||
var driverPluginNameDict = _pluginService.GetPluginList().DistinctBy(a => a.Name).ToDictionary(a => a.Name);
|
var driverPluginNameDict = _pluginService.GetPluginList().DistinctBy(a => a.Name).ToDictionary(a => a.Name);
|
||||||
ConcurrentDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
NonBlockingDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
||||||
foreach (var sheetName in sheetNames)
|
foreach (var sheetName in sheetNames)
|
||||||
{
|
{
|
||||||
#pragma warning disable CA1849
|
#pragma warning disable CA1849
|
||||||
@@ -457,7 +457,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public void SetDeviceData(HashSet<long>? dataScope, IReadOnlyDictionary<string, DeviceRuntime> deviceDicts, IReadOnlyDictionary<string, ChannelRuntime> channelDicts, Dictionary<string, ImportPreviewOutputBase> ImportPreviews, ref ImportPreviewOutput<Device> deviceImportPreview, Dictionary<string, PluginInfo> driverPluginNameDict, ConcurrentDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict, string sheetName, IEnumerable<IDictionary<string, object>> rows)
|
public void SetDeviceData(HashSet<long>? dataScope, IReadOnlyDictionary<string, DeviceRuntime> deviceDicts, IReadOnlyDictionary<string, ChannelRuntime> channelDicts, Dictionary<string, ImportPreviewOutputBase> ImportPreviews, ref ImportPreviewOutput<Device> deviceImportPreview, Dictionary<string, PluginInfo> driverPluginNameDict, NonBlockingDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict, string sheetName, IEnumerable<IDictionary<string, object>> rows)
|
||||||
{
|
{
|
||||||
#region 采集设备sheet
|
#region 采集设备sheet
|
||||||
string ImportNullError = Localizer["ImportNullError"];
|
string ImportNullError = Localizer["ImportNullError"];
|
||||||
|
@@ -34,7 +34,7 @@ string? channelName = null)
|
|||||||
|
|
||||||
var result = new Dictionary<string, object>();
|
var result = new Dictionary<string, object>();
|
||||||
result.Add(GatewayExportString.DeviceName, GetDeviceSheets(data1, deviceDicts, channelDicts, channelName));
|
result.Add(GatewayExportString.DeviceName, GetDeviceSheets(data1, deviceDicts, channelDicts, channelName));
|
||||||
ConcurrentDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
NonBlockingDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
||||||
|
|
||||||
foreach (var plugin in pluginSheetNames)
|
foreach (var plugin in pluginSheetNames)
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ IReadOnlyDictionary<long, DeviceRuntime>? deviceDicts,
|
|||||||
|
|
||||||
static async IAsyncEnumerable<Dictionary<string, object>> GetPluginSheets(
|
static async IAsyncEnumerable<Dictionary<string, object>> GetPluginSheets(
|
||||||
IAsyncEnumerable<Device> data,
|
IAsyncEnumerable<Device> data,
|
||||||
ConcurrentDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict,
|
NonBlockingDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict,
|
||||||
string? plugin)
|
string? plugin)
|
||||||
{
|
{
|
||||||
var enumerator = data.GetAsyncEnumerator();
|
var enumerator = data.GetAsyncEnumerator();
|
||||||
@@ -129,7 +129,7 @@ IReadOnlyDictionary<long, DeviceRuntime>? deviceDicts,
|
|||||||
|
|
||||||
// 获取所有驱动程序,并将驱动程序名称作为键构建字典
|
// 获取所有驱动程序,并将驱动程序名称作为键构建字典
|
||||||
var driverPluginNameDict = GlobalData.PluginService.GetPluginList().DistinctBy(a => a.Name).ToDictionary(a => a.Name);
|
var driverPluginNameDict = GlobalData.PluginService.GetPluginList().DistinctBy(a => a.Name).ToDictionary(a => a.Name);
|
||||||
ConcurrentDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
NonBlockingDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
||||||
|
|
||||||
var sheetNames = uSheetDatas.sheets.Keys.ToList();
|
var sheetNames = uSheetDatas.sheets.Keys.ToList();
|
||||||
foreach (var sheetName in sheetNames)
|
foreach (var sheetName in sheetNames)
|
||||||
|
@@ -45,7 +45,7 @@ HashSet<string> pluginSheetNames,
|
|||||||
|
|
||||||
var result = new Dictionary<string, object>();
|
var result = new Dictionary<string, object>();
|
||||||
result.Add(GatewayExportString.DeviceName, GetDeviceSheets(data, deviceDicts, channelDicts, channelName));
|
result.Add(GatewayExportString.DeviceName, GetDeviceSheets(data, deviceDicts, channelDicts, channelName));
|
||||||
ConcurrentDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
NonBlockingDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
||||||
|
|
||||||
foreach (var plugin in pluginSheetNames)
|
foreach (var plugin in pluginSheetNames)
|
||||||
{
|
{
|
||||||
@@ -130,7 +130,7 @@ string? channelName)
|
|||||||
|
|
||||||
static IEnumerable<Dictionary<string, object>> GetPluginSheets(
|
static IEnumerable<Dictionary<string, object>> GetPluginSheets(
|
||||||
IEnumerable<Device> data,
|
IEnumerable<Device> data,
|
||||||
ConcurrentDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict,
|
NonBlockingDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict,
|
||||||
string? plugin)
|
string? plugin)
|
||||||
{
|
{
|
||||||
foreach (var device in data)
|
foreach (var device in data)
|
||||||
@@ -145,7 +145,7 @@ string? channelName)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Dictionary<string, object> GetPluginRows(Device device, string? plugin, ConcurrentDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict)
|
static Dictionary<string, object> GetPluginRows(Device device, string? plugin, NonBlockingDictionary<string, (object, Dictionary<string, PropertyInfo>)> propertysDict)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> driverInfo = new();
|
Dictionary<string, object> driverInfo = new();
|
||||||
var propDict = device.DevicePropertys;
|
var propDict = device.DevicePropertys;
|
||||||
|
@@ -110,7 +110,7 @@ internal interface IDeviceService
|
|||||||
/// <returns>保存是否成功的异步任务</returns>
|
/// <returns>保存是否成功的异步任务</returns>
|
||||||
Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type);
|
Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type);
|
||||||
|
|
||||||
void SetDeviceData(HashSet<long>? dataScope, IReadOnlyDictionary<string, DeviceRuntime> deviceDicts, IReadOnlyDictionary<string, ChannelRuntime> channelDicts, Dictionary<string, ImportPreviewOutputBase> ImportPreviews, ref ImportPreviewOutput<Device> deviceImportPreview, Dictionary<string, PluginInfo> driverPluginNameDict, ConcurrentDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict, string sheetName, IEnumerable<IDictionary<string, object>> rows);
|
void SetDeviceData(HashSet<long>? dataScope, IReadOnlyDictionary<string, DeviceRuntime> deviceDicts, IReadOnlyDictionary<string, ChannelRuntime> channelDicts, Dictionary<string, ImportPreviewOutputBase> ImportPreviews, ref ImportPreviewOutput<Device> deviceImportPreview, Dictionary<string, PluginInfo> driverPluginNameDict, NonBlockingDictionary<string, (Type, Dictionary<string, PropertyInfo>, Dictionary<string, PropertyInfo>)> propertysDict, string sheetName, IEnumerable<IDictionary<string, object>> rows);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存是否输出日志和日志等级
|
/// 保存是否输出日志和日志等级
|
||||||
|
@@ -26,7 +26,7 @@ internal sealed class ChannelThreadManage : IChannelThreadManage
|
|||||||
_logger = App.RootServices.GetService<Microsoft.Extensions.Logging.ILoggerFactory>().CreateLogger($"ChannelThreadService");
|
_logger = App.RootServices.GetService<Microsoft.Extensions.Logging.ILoggerFactory>().CreateLogger($"ChannelThreadService");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConcurrentDictionary<long, IDeviceThreadManage> DeviceThreadManages { get; } = new();
|
public NonBlockingDictionary<long, IDeviceThreadManage> DeviceThreadManages { get; } = new();
|
||||||
|
|
||||||
#region 设备管理
|
#region 设备管理
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ namespace ThingsGateway.Gateway.Application;
|
|||||||
|
|
||||||
public interface IChannelThreadManage : IAsyncDisposable
|
public interface IChannelThreadManage : IAsyncDisposable
|
||||||
{
|
{
|
||||||
ConcurrentDictionary<long, IDeviceThreadManage> DeviceThreadManages { get; }
|
NonBlockingDictionary<long, IDeviceThreadManage> DeviceThreadManages { get; }
|
||||||
|
|
||||||
Task RestartChannelAsync(ChannelRuntime channelRuntime);
|
Task RestartChannelAsync(ChannelRuntime channelRuntime);
|
||||||
Task RestartChannelAsync(IList<ChannelRuntime> channelRuntimes);
|
Task RestartChannelAsync(IList<ChannelRuntime> channelRuntimes);
|
||||||
|
@@ -152,18 +152,18 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务
|
/// 任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ConcurrentDictionary<long, TaskSchedulerLoop> DriverTasks { get; } = new();
|
internal NonBlockingDictionary<long, TaskSchedulerLoop> DriverTasks { get; } = new();
|
||||||
|
|
||||||
public int TaskCount => DriverTasks.Count;
|
public int TaskCount => DriverTasks.Count;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取消令箭列表
|
/// 取消令箭列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<long, CancellationTokenSource> CancellationTokenSources { get; set; } = new();
|
private NonBlockingDictionary<long, CancellationTokenSource> CancellationTokenSources { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 插件列表
|
/// 插件列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<long, DriverBase> Drivers { get; set; } = new();
|
private NonBlockingDictionary<long, DriverBase> Drivers { get; set; } = new();
|
||||||
|
|
||||||
public IChannelThreadManage ChannelThreadManage { get; internal set; }
|
public IChannelThreadManage ChannelThreadManage { get; internal set; }
|
||||||
|
|
||||||
|
@@ -62,7 +62,7 @@ internal sealed class PluginService : IPluginService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 插件文件名称/插件域
|
/// 插件文件名称/插件域
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<string, (AssemblyLoadContext AssemblyLoadContext, Assembly Assembly)> _assemblyLoadContextDict { get; } = new();
|
private NonBlockingDictionary<string, (AssemblyLoadContext AssemblyLoadContext, Assembly Assembly)> _assemblyLoadContextDict { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主程序上下文中的插件FullName/插件Type
|
/// 主程序上下文中的插件FullName/插件Type
|
||||||
@@ -73,7 +73,7 @@ internal sealed class PluginService : IPluginService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 插件FullName/插件Type
|
/// 插件FullName/插件Type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<string, Type> _driverBaseDict { get; } = new();
|
private NonBlockingDictionary<string, Type> _driverBaseDict { get; } = new();
|
||||||
|
|
||||||
#region public
|
#region public
|
||||||
|
|
||||||
@@ -615,7 +615,7 @@ internal sealed class PluginService : IPluginService
|
|||||||
// 获取私有字段
|
// 获取私有字段
|
||||||
FieldInfo fieldInfo = typeof(ResourceManagerStringLocalizerFactory).GetField("_localizerCache", BindingFlags.Instance | BindingFlags.NonPublic);
|
FieldInfo fieldInfo = typeof(ResourceManagerStringLocalizerFactory).GetField("_localizerCache", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
// 获取字段的值
|
// 获取字段的值
|
||||||
var dictionary = (ConcurrentDictionary<string, ResourceManagerStringLocalizer>)fieldInfo.GetValue(App.StringLocalizerFactory);
|
var dictionary = (NonBlockingDictionary<string, ResourceManagerStringLocalizer>)fieldInfo.GetValue(App.StringLocalizerFactory);
|
||||||
foreach (var item in _assemblyLoadContextDict)
|
foreach (var item in _assemblyLoadContextDict)
|
||||||
{
|
{
|
||||||
var ids = item.Value.Assembly.ExportedTypes.Select(b => b.AssemblyQualifiedName).ToHashSet();
|
var ids = item.Value.Assembly.ExportedTypes.Select(b => b.AssemblyQualifiedName).ToHashSet();
|
||||||
|
@@ -102,7 +102,7 @@ public static class PluginServiceUtil
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过实体赋值到字典中
|
/// 通过实体赋值到字典中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Dictionary<long, Dictionary<string, string>> SetDict(ConcurrentDictionary<long, ModelValueValidateForm>? models)
|
public static Dictionary<long, Dictionary<string, string>> SetDict(NonBlockingDictionary<long, ModelValueValidateForm>? models)
|
||||||
{
|
{
|
||||||
Dictionary<long, Dictionary<string, string>> results = new();
|
Dictionary<long, Dictionary<string, string>> results = new();
|
||||||
models ??= new();
|
models ??= new();
|
||||||
|
@@ -54,7 +54,7 @@ internal sealed class RpcService : IRpcService
|
|||||||
Dictionary<VariableRuntime, string> memoryVariables = new();
|
Dictionary<VariableRuntime, string> memoryVariables = new();
|
||||||
|
|
||||||
// 用于存储结果的并发字典
|
// 用于存储结果的并发字典
|
||||||
ConcurrentDictionary<string, Dictionary<string, IOperResult>> results = new();
|
NonBlockingDictionary<string, Dictionary<string, IOperResult>> results = new();
|
||||||
deviceDatas.ForEach(a => results.TryAdd(a.Key, new()));
|
deviceDatas.ForEach(a => results.TryAdd(a.Key, new()));
|
||||||
|
|
||||||
// 对每个要操作的变量进行检查和处理(内存变量)
|
// 对每个要操作的变量进行检查和处理(内存变量)
|
||||||
|
@@ -41,9 +41,9 @@ public class AlarmChangedTriggerNode : VariableNode, ITriggerNode, IDisposable
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentList<AlarmChangedTriggerNode>>> AlarmChangedTriggerNodeDict = new();
|
public static NonBlockingDictionary<string, NonBlockingDictionary<string, ConcurrentList<AlarmChangedTriggerNode>>> AlarmChangedTriggerNodeDict = new();
|
||||||
|
|
||||||
public static ConcurrentDictionary<AlarmChangedTriggerNode, Func<NodeOutput, CancellationToken, Task>> FuncDict = new();
|
public static NonBlockingDictionary<AlarmChangedTriggerNode, Func<NodeOutput, CancellationToken, Task>> FuncDict = new();
|
||||||
|
|
||||||
public static BlockingCollection<AlarmVariable> AlarmVariables = new();
|
public static BlockingCollection<AlarmVariable> AlarmVariables = new();
|
||||||
static AlarmChangedTriggerNode()
|
static AlarmChangedTriggerNode()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user