C# 天门冬氨酰可数法
我得到了以下扩展方法:C# 天门冬氨酰可数法,c#,multithreading,linq,thread-safety,C#,Multithreading,Linq,Thread Safety,我得到了以下扩展方法: static class ExtensionMethods { public static IEnumerable<IEnumerable<T>> Subsequencise<T>( this IEnumerable<T> input, int subsequenceLength) { var enumerator = input.GetEnumerator()
static class ExtensionMethods
{
public static IEnumerable<IEnumerable<T>> Subsequencise<T>(
this IEnumerable<T> input,
int subsequenceLength)
{
var enumerator = input.GetEnumerator();
SubsequenciseParameter parameter = new SubsequenciseParameter
{
Next = enumerator.MoveNext()
};
while (parameter.Next)
yield return getSubSequence(
enumerator,
subsequenceLength,
parameter);
}
private static IEnumerable<T> getSubSequence<T>(
IEnumerator<T> enumerator,
int subsequenceLength,
SubsequenciseParameter parameter)
{
do
{
lock (enumerator) // this lock makes it "work"
{ // removing this causes exceptions.
if (parameter.Next)
yield return enumerator.Current;
}
} while ((parameter.Next = enumerator.MoveNext())
&& --subsequenceLength > 0);
}
// Needed since you cant use out or ref in yield-return methods...
class SubsequenciseParameter
{
public bool Next { get; set; }
}
}
但是,由于一些线程“太晚”并进入第一个收益回报,因此在这两个线程之间有一些空行
我试着把更多的锁放在各处,但是我无法将这项工作与as并行结合起来
很明显,这个例子根本不能证明使用as parallel是合理的。这只是为了演示如何调用该方法。问题在于使用迭代器是延迟计算的,因此您返回一个延迟计算的迭代器,该迭代器从多个线程使用 您可以通过如下方式重写方法来解决此问题:
public static IEnumerable<IEnumerable<T>> Subsequencise<T>(this IEnumerable<T> input, int subsequenceLength)
{
var syncObj = new object();
var enumerator = input.GetEnumerator();
if (!enumerator.MoveNext())
{
yield break;
}
List<T> currentList = new List<T> { enumerator.Current };
int length = 1;
while (enumerator.MoveNext())
{
if (length == subsequenceLength)
{
length = 0;
yield return currentList;
currentList = new List<T>();
}
currentList.Add(enumerator.Current);
++length;
}
yield return currentList;
}
公共静态IEnumerable子序列(此IEnumerable输入,int subsequenceLength)
{
var syncObj=新对象();
var枚举器=input.GetEnumerator();
如果(!enumerator.MoveNext())
{
屈服断裂;
}
List currentList=新列表{enumerator.Current};
整数长度=1;
while(枚举数.MoveNext())
{
if(长度==子序列长度)
{
长度=0;
收益率返回列表;
currentList=新列表();
}
currentList.Add(枚举器.Current);
++长度;
}
收益率返回列表;
}
这执行相同的函数,但不使用迭代器实现“嵌套的”
IEnumerable
,从而避免了问题。请注意,这也避免了锁定以及自定义的子序列参数
类型。答案不错,但是值得一提的是,它附带了价格累积。@BartoszKP累积?唯一的累积值是“嵌套”序列,它们将非常小。整个过程仍在进行中。。。这里应该很少有“价格”关联(当然,除非您处理的是非常大的序列大小),价格是大还是小取决于使用上下文。根据我的经验,当您需要批处理时,通常序列非常大,OP的解决方案不需要任何累加(确实,它不起作用:)。我不是说这是一个很大的缺点——正如我所说,我发现答案很好:)@BartoszKP积累只发生在单个批次中,而不是整个序列中。例如,如果您有100000000个元素,并且取5个元素的序列,那么我只存储1个包含5个元素的List
。这就是为什么有低开销。百万美元的资金仍然在流程中流动。是的,我理解你的代码,我没有说开销不低。我更倾向于考虑10批100000个元素列表,或1000x1000。再说一次,我不是说这是个大问题。。。
public static IEnumerable<IEnumerable<T>> Subsequencise<T>(this IEnumerable<T> input, int subsequenceLength)
{
var syncObj = new object();
var enumerator = input.GetEnumerator();
if (!enumerator.MoveNext())
{
yield break;
}
List<T> currentList = new List<T> { enumerator.Current };
int length = 1;
while (enumerator.MoveNext())
{
if (length == subsequenceLength)
{
length = 0;
yield return currentList;
currentList = new List<T>();
}
currentList.Add(enumerator.Current);
++length;
}
yield return currentList;
}