C#: Как я могу сделать IEnumerable <T> ориентированным на многопотоковое исполнение?

Необходимо быть ясными на определении "случайных". Каковы Ваши ограничения на получающуюся матрицу? Вы хотите, чтобы коэффициенты были однородно или обычно распределены? Вы хотите, чтобы собственные значения имели конкретное распределение? (и т.д.).

существует много способов генерировать положительные полуопределенные матрицы M, включая:

  1. , Учитывая произвольную матрицу A, вычислите M = T глоток> (построение разложение Cholesky )
  2. , Учитывая произвольную диагональную матрицу S с неотрицательными диагональными записями и ортонормированной матрицей Q того же размера, вычислите M = QSQ T глоток> (построение сингулярное разложение )

По числовым причинам, я, вероятно, выбрал бы второй подход путем генерации диагональной матрицы с желаемыми свойствами, затем генерируя Q как состав многих отражения Домовладельца (генерируйте случайный вектор v, масштаб к единичной длине, H = я - 2vv T глоток>); я подозреваю, что Вы хотели бы использовать K * N, где N является размером матрицы M, и K является числом между 1.5-3 (я предполагаю на этом), который гарантирует, что это имеет достаточно степеней свободы.

Вы могли также генерировать ортонормированную матрицу Q использование вращения Givens : выберите 2 отличных значения от 1 до N и генерируйте вращение Givens вокруг той пары осей с углом, равномерно распределенным от 0 до 2 * пи. Тогда возьмите K * N их (то же обоснование как выше абзаца), и их состав приводит к Q.

редактирование: я был бы предположение (не уверенный), что, если у Вас есть коэффициенты, которые независимо сгенерированы и обычно распределяются, тогда матрица в целом "обычно распределялась бы" (независимо от того, что это означает). Это верно для векторов, по крайней мере. (N независимо сгенерированные Гауссовы случайные переменные, один для каждого компонента, дает Вам Гауссов случайный вектор), Это не верно для равномерно распределенных компонентов.

40
задан Svish 22 October 2009 в 08:25
поделиться

5 ответов

При этом существует внутренняя проблема, потому что IEnumerator имеет как MoveNext () , так и Current . Вам действительно нужен один вызов, например:

bool TryMoveNext(out T value)

, в этот момент вы можете атомарно перейти к следующему элементу и получить значение. Реализовать это и по-прежнему использовать yield может быть непросто ... Я все же подумаю над этим. Я думаю, вам нужно обернуть «небезопасный» итератор в потокобезопасный, который атомарно выполняет MoveNext () и Current для реализации интерфейса, показанного выше. Я не знаю, как бы вы затем обернули этот интерфейс обратно в IEnumerator , чтобы вы могли использовать его в foreach , хотя ...

Если вы '

41
ответ дан 27 November 2019 в 01:54
поделиться

Я предполагаю, что вам нужен перечислитель с сохранением потоков, поэтому вам, вероятно, следует реализовать его.

0
ответ дан 6 July 2019 в 16:42
поделиться

Ну, я не уверен, но, может быть, с некоторыми блокировками в вызывающем?

Черновик:

Monitor.Enter(syncRoot);
foreach (var item in enumerable)
{
  Monitor.Exit(syncRoot);
  //Do something with item
  Monitor.Enter(syncRoot);
}
Monitor.Exit(syncRoot);
0
ответ дан 27 November 2019 в 01:54
поделиться

Я подумал, что вы не можете сделать ключевое слово yield потокобезопасным, если не сделаете его зависимым от уже поточно-безопасного источника значений:

public interface IThreadSafeEnumerator<T>
{
    void Reset();
    bool TryMoveNext(out T value);
}

public class ThreadSafeUIntEnumerator : IThreadSafeEnumerator<uint>, IEnumerable<uint>
{
    readonly object sync = new object();

    uint n;

    #region IThreadSafeEnumerator<uint> Members
    public void Reset()
    {
        lock (sync)
        {
            n = 0;
        }
    }

    public bool TryMoveNext(out uint value)
    {
        bool success = false;

        lock (sync)
        {
            if (n < 100)
            {
                value = n++;
                success = true;
            }
            else
            {
                value = uint.MaxValue;
            }
        }

        return success;
    }
    #endregion
    #region IEnumerable<uint> Members
    public IEnumerator<uint> GetEnumerator()
    {
        //Reset(); // depends on what behaviour you want
        uint value;
        while (TryMoveNext(out value))
        {
            yield return value;
        }
    }
    #endregion
    #region IEnumerable Members
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        //Reset(); // depends on what behaviour you want
        uint value;
        while (TryMoveNext(out value))
        {
            yield return value;
        }
    }
    #endregion
}

Вам нужно будет решить, должно ли каждое типичное инициирование счетчика сбрасывать последовательность или это должен делать код клиента.

0
ответ дан 27 November 2019 в 01:54
поделиться

Вместо использования yield вы можете просто возвращать полную последовательность каждый раз:

return Enumerable.Range (0, 100) .Cast () .ToArray ();

-2
ответ дан 27 November 2019 в 01:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: