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;
}