简体   繁体   English

带有AsParallel的IEnumerable方法

[英]IEnumerable Method with AsParallel

I got the following extension method: 我得到以下扩展方法:

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

Its purpose is to split a sequence into subsequences of a given size. 其目的是将序列分成给定大小的子序列。

Calling it like this: 像这样调用它:

foreach (var sub in "abcdefghijklmnopqrstuvwxyz"
                    .Subsequencise(3)
                    .**AsParallel**()
                    .Select(sub =>new String(sub.ToArray()))
{
    Console.WriteLine(sub);
}

Console.ReadKey();

works, however there are some empty lines in-between since some of the threads are "too late" and enter the first yield return. 可以,但是由于某些线程“为时已晚”并输入第一个收益率返回值,因此它们之间有一些空行。

I tried putting more locks everywhere, however I cannot achieve to make this work correct in combination with as parallel. 我尝试到处都放更多的锁,但是我无法通过并行操作来使这项工作正确进行。

It's obvious that this example doesn't justify the use of as parallel at all. 显然,此示例完全没有理由使用as并行。 It is just to demonstrate how the method could be called. 只是为了演示如何调用该方法。

The problem is that using iterators is lazy evaluated, so you return a lazily evaluated iterator which gets used from multiple threads. 问题在于使用迭代器是延迟计算的,因此您返回了一个延迟评估的迭代器,该迭代器已从多个线程使用。

You can fix this by rewriting your method as follows: 您可以通过如下重写方法来解决此问题:

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

This performs the same function, but doesn't use an iterator to implement the "nested" IEnumerable<T> , avoiding the problem. 这执行相同的功能,但是不使用迭代器来实现“嵌套的” IEnumerable<T> ,从而避免了该问题。 Note that this also avoids the locking as well as the custom SubsequenciseParameter type. 请注意,这还避免了锁定以及自定义SubsequenciseParameter类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM