here's my whole codes,I've deleted multiThreadings part,but it still warns the same message:
using ExcelDna.Integration;
using ExcelDna.Registration;
using System.Buffers;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace TestDnaNative110p1
{
public static class MyFunctions
{
private static int maxDepthReached = 0;
private static int _numberCount;
private static long _longTarget;
private static int _resultsLimit;
private static long[] _intNumbersArray = [];
internal static CancellationTokenSource _cts = new();
internal static List<List<long>> _results = [];
private static int _faultRange;
private static long _fixedTargetAdd;
private static long _fixedTargetSub;
private static long _numberSign;
private static long[] _sourceNumbers = [];
private static Dictionary<int, List<List<long>>> _resultsCache = [];
private static Dictionary<int, long> _numberSignCache = [];
private static int _resultHashCode;
private static bool _isMultiThreading;
private static long _recursiveCount = 0;
private static readonly Lock _lock = new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryGetNumericValue(object? cell, out double value)
{
value = 0;
if (cell is null)
return false;
switch (cell)
{
case sbyte or byte or short or ushort or int or uint or long or ulong
or float or double or decimal:
value = Convert.ToDouble(cell);
return true;
case string s:
return double.TryParse(s, out value);
default:
return false;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GenerateCombinationHash(long[] combination, int length)
{
HashCode hash = new();
for (int i = 0; i < length; i++)
{
hash.Add(combination[i]);
}
return hash.ToHashCode();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void PreProcessData(ref object[,] RefArray, double TargetValue, int maxCombinations, int faultTolerance,
double maxRunTime, int ignoreNegative, int returnMode, int maxDepth, int maxExpension)
{
int negativeCount = 0;
List<long> intNumbers = [];
_sourceNumbers = new long[RefArray.Length];
long negetiveTotal = 0;
long positiveTotal = 0;
int idx = 0;
int validCount = 0;
foreach (var cell in RefArray)
{
if (TryGetNumericValue(cell, out double num))
{
validCount++;
if (num != 0)
{
long scaled = (long)Math.Round(num * 100);
if (ignoreNegative == 1)
{
intNumbers.Add(scaled);
}
else
{
if (scaled > 0)
intNumbers.Add(scaled);
}
//intNumbers.Add(scaled);
_sourceNumbers[idx] = scaled;
if (num < 0)
{
negetiveTotal += scaled;
negativeCount++;
}
else
{
positiveTotal += scaled;
}
}
}
idx++;
}
if (validCount == 0)
return;
//候选数字按降序排列
intNumbers.Sort();
intNumbers.Reverse();
_faultRange = Math.Abs(faultTolerance * 100);
_resultsLimit = maxCombinations;
if (-negetiveTotal > positiveTotal && ignoreNegative == 1)
//if (negativeCount > intNumbers.Count / 2)
{
_numberSign = -1;
_longTarget = -(long)Math.Round(TargetValue * 100); // 将目标值转换为整数
for (int i = 0; i < intNumbers.Count; i++)
{
intNumbers[i] = -intNumbers[i];
}
}
else
{
_numberSign = 1;
_longTarget = (long)Math.Round(TargetValue * 100); // 将目标值转换为整数
}
//_longTarget = intTargetValue;
_fixedTargetAdd = _longTarget + _faultRange;
_fixedTargetSub = _longTarget - _faultRange;
_numberCount = intNumbers.Count;
_intNumbersArray = intNumbers.ToArray();
//根据候选数字、目标和、结果数量上限、容错值和组合包含的最大数字个数生成结果哈希码
_resultHashCode = GenerateResultsHash(_intNumbersArray, TargetValue, maxCombinations, faultTolerance, maxDepth);
}
private static int GenerateResultsHash(long[] ValidNumbers, double target, int resultsCount, int faultTolerance, int maxDepth)
{
HashCode hash = new();
foreach (var item in ValidNumbers)
{
hash.Add(item);
}
hash.Add(target);
hash.Add(resultsCount);
hash.Add(faultTolerance);
hash.Add(maxDepth);
return hash.ToHashCode();
}
[ExcelAsyncFunction]
public static async Task<object> SubsetSUMbackground(object RefRange, double TargetValue, int maxCombinations = 1, int faultTolerance = 0,
int displayMode = 0, int enableMultiThreadings = 0, double maxRunTime = 10.0, bool forVBA = false, int ignoreNegative = 0,
int returnMode = 0, bool isCache = true, bool isByRibbon = false, int maxDepth = 0, int maxExpension = 0)
{
_results.Clear();
const int adaptiveTime = 400; // 自适应模式初始单线程运行时间,单位毫秒
var finishedEvent = new ManualResetEventSlim(false);// 创建一个信号量,用于通知看门狗“任务已完成”
_ = Task.Factory.StartNew(() =>
{
_cts = new CancellationTokenSource();
TimeSpan timeLimit = new TimeSpan();
if (enableMultiThreadings == 0)//自适应模式默认先以单线程运行400毫秒
timeLimit = TimeSpan.FromMilliseconds(adaptiveTime);
else
timeLimit = TimeSpan.FromSeconds(maxRunTime);
if (!finishedEvent.Wait(timeLimit))
{
_cts.Cancel();
}
finishedEvent.Dispose();
}, TaskCreationOptions.LongRunning);
int currentRow = 0;
int currentColumn = 0;
currentRow = 1;
currentColumn = 1;
var seenHashSet = new HashSet<int>();
if (RefRange is not object[,] arr)
return "#未找到有效的候选数字";
if (arr.GetLength(1) > 1 && returnMode != 0)
return "#按位置返回仅支持按列排布的候选数字";
_resultHashCode = 0;
PreProcessData(ref arr, TargetValue, maxCombinations, faultTolerance, maxRunTime, ignoreNegative, returnMode, maxDepth, maxExpension);
if (_numberCount == 0)
return "#未找到有效的候选数字";
maxDepthReached = maxDepth == 0 ? _numberCount : maxDepth - 1;
if (isCache && _resultsCache.TryGetValue(_resultHashCode, out var value2))
{
_results = new List<List<long>>(value2); ;
_numberSign = _numberSignCache[_resultHashCode];
return ProcessResults(currentRow, currentColumn, maxCombinations, displayMode, forVBA, returnMode, ignoreNegative, isByRibbon);
}
var remainingPositiveSum = new long[_numberCount];
var remainingNegativeSum = new long[_numberCount];
long positiveSum = 0;
long negativeSum = 0;
for (int i = _numberCount - 1; i >= 0; i--)
{
if (_intNumbersArray[i] > 0)
positiveSum += _intNumbersArray[i];
else if (_intNumbersArray[i] < 0)
negativeSum += _intNumbersArray[i]; // 负值
remainingPositiveSum[i] = _fixedTargetSub - positiveSum;
remainingNegativeSum[i] = ignoreNegative == 0 ? _fixedTargetAdd : _fixedTargetAdd - negativeSum;
}
return await Task.Run(() =>
{
var stopwatch = Stopwatch.StartNew();
Action<int, int, long[], HashSet<int>, long, long[], long[]> searchStrategy;
if (faultTolerance != 0)
{
searchStrategy = _numberCount > 5000 ? DepthFirstSearchWithFaultLoop : DepthFirstSearchWithFault;
}
else
{
searchStrategy = _numberCount > 5000 ? DepthFirstSearchLoop : DepthFirstSearch;
}
_isMultiThreading = false;
long[] combination = new long[_numberCount];
for (int i = 0; i < _numberCount; i++)
{
combination[0] = _intNumbersArray[i];
searchStrategy(i + 1, 1, combination, seenHashSet, _intNumbersArray[i], remainingPositiveSum, remainingNegativeSum);
}
finishedEvent.Set();
if (isCache && _results.Count > 0)
{
int currentHashCode = GenerateResultsHash(_intNumbersArray, TargetValue, maxCombinations, faultTolerance, maxDepth);
_resultsCache[currentHashCode] = new List<List<long>>(_results); ; // 深拷贝以防后续修改
_numberSignCache[currentHashCode] = _numberSign;
}
return ProcessResults(currentRow, currentColumn, maxCombinations, displayMode, forVBA, returnMode, ignoreNegative, isByRibbon);
});
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static object ProcessResults(int startRow, int startColumn, int maxCombinations, int displayMode, bool isVBA, int returnmode, int ignoreNegative, bool isRibbon)
{
if (_results.Count == 0)
{
return ignoreNegative == 0 ? "#无解,请尝试计入负数" : "#无解";
}
else
{
if (returnmode == 0)
{
double[,] resultArray;
int resultCount = Math.Min(_results.Count, maxCombinations);
int maxSize = 0;
if (_results.Count > 0)
{
foreach (var r in _results)
{
if (r.Count > maxSize)
{
maxSize = r.Count;
}
}
}
var sortedResults = new List<List<long>>(_results);
sortedResults.Sort((a, b) =>
{
int compareCount = a.Count.CompareTo(b.Count);
if (compareCount != 0)
{
return compareCount;
}
long firstA = a.Count > 0 ? a[0] : 0; // 等价于 FirstOrDefault
long firstB = b.Count > 0 ? b[0] : 0;
return firstA.CompareTo(firstB);
});
// 2. 替换原来的 results
_results = sortedResults;
int count = 0;
if (displayMode == 1)
{
resultArray = new double[_results.Count, maxSize]; // 按行显示
foreach (var item in _results)
{
for (int j = 0; j < item.Count; j++)
{
double originalValue = _numberSign * item[j] / 100.0;
resultArray[count, j] = originalValue;
}
count++;
}
}
else // displayMode为2
{
resultArray = new double[maxSize, _results.Count]; // 按列显示
foreach (var item in _results)
{
for (int j = 0; j < item.Count; j++)
{
double originalValue = _numberSign * item[j] / 100.0;
resultArray[j, count] = originalValue;
}
count++;
}
}
return resultArray;
}
else
{
string[,] resultArray = new string[_sourceNumbers.Length, _results.Count];
bool[] used = new bool[_sourceNumbers.Length];
var sortedResults = new List<List<long>>(_results);
sortedResults.Sort((a, b) =>
{
int compareCount = a.Count.CompareTo(b.Count);
if (compareCount != 0)
{
return compareCount;
}
long firstA = a.Count > 0 ? a[0] : 0; // 等价于 FirstOrDefault
long firstB = b.Count > 0 ? b[0] : 0;
return firstA.CompareTo(firstB);
});
_results = sortedResults;
int count = 0;
foreach (var combination in _results)
{
Array.Clear(used, 0, used.Length); // 每组重置
foreach (var value in combination)
{
long key = value; //* _numberSign;
for (int i = 0; i < _sourceNumbers.Length; i++)
{
if (!used[i] && _sourceNumbers[i] * _numberSign == key)
{
resultArray[i, count] = "●";
used[i] = true;
break;
}
}
}
count++;
}
return resultArray;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DepthFirstSearchWithFaultLoop(int startIndex, int depth, long[] combination,
HashSet<int> seenCombinations, long currentSum, long[] remainingPositiveSum, long[] remainingNegativeSum)
{
var indexStack = new Stack<int>();
int i = startIndex;
while (true)
{
if (_cts.Token.IsCancellationRequested || _results.Count >= _resultsLimit || depth > maxDepthReached)
{
return;
}
if (i < _numberCount)
{
if (currentSum < remainingPositiveSum[i] || currentSum > remainingNegativeSum[i])
{
i = _numberCount;
continue;
}
combination[depth] = _intNumbersArray[i];
currentSum += _intNumbersArray[i];
long temSum = Math.Abs(currentSum - _longTarget);
if (temSum <= _faultRange)
{
int combinationHash = GenerateCombinationHash(combination, depth);
if (_isMultiThreading)
{
lock (_lock)
{
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
}
}
else
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
currentSum -= _intNumbersArray[i];
i++;
}
else
{
indexStack.Push(i);
depth++;
i = i + 1;
}
}
else
{
if (indexStack.Count == 0)
{
return;
}
int last_i = indexStack.Pop();
depth--;
currentSum -= _intNumbersArray[last_i];
i = last_i + 1;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DepthFirstSearchWithFault(int startIndex, int depth, long[] combination,
HashSet<int> seenCombinations, long currentSum, long[] remainingPositiveSum, long[] remainingNegativeSum)
{
long temSum = Math.Abs(currentSum - _longTarget);
if (temSum <= _faultRange)
{
int combinationHash = GenerateCombinationHash(combination, depth);
if (_isMultiThreading)
{
lock (_lock)
{
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
}
}
else
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
return;
}
for (int i = startIndex; i < _numberCount; i++)
{
if (_cts.Token.IsCancellationRequested || _results.Count >= _resultsLimit || depth > maxDepthReached)
return;
if (currentSum < remainingPositiveSum[i])
return;
if (currentSum > remainingNegativeSum[i])
return;
combination[depth] = _intNumbersArray[i];
DepthFirstSearchWithFault(i + 1, depth + 1, combination, seenCombinations, currentSum + _intNumbersArray[i], remainingPositiveSum, remainingNegativeSum);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DepthFirstSearchLoop(int startIndex, int depth, long[] combination,
HashSet<int> seenCombinations, long currentSum, long[] remainingPositiveSum, long[] remainingNegativeSum)
{
var indexStack = new Stack<int>();
int i = startIndex;
while (true)
{
if (_cts.Token.IsCancellationRequested || _results.Count >= _resultsLimit || depth > maxDepthReached)
{
return;
}
if (i < _numberCount)
{
if (currentSum < remainingPositiveSum[i] || currentSum > remainingNegativeSum[i])
{
i = _numberCount;
continue;
}
combination[depth] = _intNumbersArray[i];
currentSum += _intNumbersArray[i];
if (currentSum == _longTarget)
{
int combinationHash = GenerateCombinationHash(combination, depth + 1);
if (_isMultiThreading)
{
lock (_lock)
{
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
}
}
else
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
currentSum -= _intNumbersArray[i];
i++;
}
else
{
indexStack.Push(i);
depth++;
i = i + 1;
}
}
else
{
if (indexStack.Count == 0)
{
return;
}
int last_i = indexStack.Pop();
depth--;
currentSum -= _intNumbersArray[last_i];
i = last_i + 1;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DepthFirstSearch(int startIndex, int depth, long[] combination,
HashSet<int> seenCombinations, long currentSum, long[] remainingPositiveSum, long[] remainingNegativeSum)
{
if (currentSum == _longTarget)
{
if (_isMultiThreading)
{
lock (_lock)
{
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
}
}
else
TryAddResult(GenerateCombinationHash(combination, depth), combination, depth, seenCombinations);
return;
}
for (int i = startIndex; i < _numberCount; i++)
{
if (_cts.Token.IsCancellationRequested || _results.Count >= _resultsLimit || depth > maxDepthReached)
return;
if (currentSum < remainingPositiveSum[i])
return;
if (currentSum > remainingNegativeSum[i])
return;
combination[depth] = _intNumbersArray[i];
DepthFirstSearch(i + 1, depth + 1, combination, seenCombinations, currentSum + _intNumbersArray[i], remainingPositiveSum, remainingNegativeSum);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void TryAddResult(int hash, long[] combination, int depth, HashSet<int> seenCombinations)
{
if (seenCombinations.Add(hash))
{
var list = new List<long>(depth);
for (int i = 0; i < depth; i++)
{
list.Add(combination[i]);
}
_results.Add(list);
}
}
}
}