Почему является Счетным. Диапазон быстрее, чем прямой цикл урожая?

 /**
 * Get a shared preferences file named Const.SHARED_PREFERENCES_FILE_NAME, keys added to it must be unique
 *
 * @param ctx
 * @return the shared preferences
 */
public static SharedPreferences getSharedPreferences(Context ctx) {
    return ctx.getSharedPreferences(Const.SHARED_PREFERENCES_FILE_NAME, Context.MODE_PRIVATE);
}

public static void cacheBoolean(Context ctx, String k, Boolean v) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    prefs.edit().putBoolean(k, v).apply();
}

public static Boolean getCachedBoolean(Context ctx, String k, Boolean defaultValue) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    return prefs.getBoolean(k, defaultValue);
}

public static void cacheString(Context ctx, String k, String v) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    prefs.edit().putString(k, v).apply();
}

public static String getCachedString(Context ctx, String k, String defaultValue) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    return prefs.getString(k, defaultValue);
}

public static void cacheInt(Context ctx, String k, int v) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    prefs.edit().putInt(k, v).apply();
}

public static int getCachedInt(Context ctx, String k, int defaultValue) {
    SharedPreferences prefs = getSharedPreferences(ctx);
    return prefs.getInt(k, defaultValue);
}

public static void clearCachedKey(Context context, String key) {
    getSharedPreferences(context).edit().remove(key).apply();
}
11
задан luke 25 August 2010 в 15:14
поделиться

4 ответа

Почему должен Enumerable.Range будьте немного медленнее, чем Ваше самодельное GetIntRange? На самом деле, если Enumerable.Range были определены как

public static class Enumerable {
    public static IEnumerable<int> Range(int start, int count) {
        var end = start + count;
        for(var current = start; current < end; ++current) {
            yield return current;
        }
    }
}

затем это должно быть точно с такой скоростью, как Ваше самодельное GetIntRange. Это - на самом деле ссылочная реализация для Enumerable.Range, отсутствуйте любые приемы со стороны компилятора или программиста.

Можно хотеть сравнить Ваш GetIntRange и System.Linq.Enumerable.Range со следующей реализацией (конечно, скомпилируйте в режиме выпуска, как Rob указывает). Эта реализация может быть немного оптимизирована относительно того, что компилятор генерировал бы от блока итератора.

public static class Enumerable {
    public static IEnumerable<int> Range(int start, int count) {
        return new RangeEnumerable(start, count);
    }
    private class RangeEnumerable : IEnumerable<int> {
        private int _Start;
        private int _Count;
        public RangeEnumerable(int start, int count) {
            _Start = start;
            _Count = count;
        }
        public virtual IEnumerator<int> GetEnumerator() {
            return new RangeEnumerator(_Start, _Count);
        }
        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
    }
    private class RangeEnumerator : IEnumerator<int> {
        private int _Current;
        private int _End;
        public RangeEnumerator(int start, int count) {
            _Current = start - 1;
            _End = start + count;
        }
        public virtual void Dispose() {
            _Current = _End;
        }
        public virtual void Reset() {
            throw new NotImplementedException();
        }
        public virtual bool MoveNext() {
            ++_Current;
            return _Current < _End;
        }
        public virtual int Current { get { return _Current; } }
        object IEnumerator.Current { get { return Current; } }
    }
}
11
ответ дан 3 December 2019 в 05:14
поделиться

Мое предположение - то, что Вы работаете в отладчике. Вот мои результаты, создав из командной строки с "/o +/debug-"

time = 142; result = 987459712
time = 1590; result = 987459712
time = 1792; result = 987459712

Существуют все еще незначительные различия, но это как не объявлено. Внедрения блока итератора не вполне так же эффективны как нестандартное решение, но они довольно хороши.

5
ответ дан 3 December 2019 в 05:14
поделиться

Принятие этого является выполнением сборки конечных версий, иначе все сравнения прочь, поскольку JIT не будет выкладываться полностью.

Вы могли посмотреть на блок с отражателем и видеть то, что оператор 'урожая' расширяется также. Компилятор будет создавать класс для инкапсуляции итератора. Возможно, существует больше обслуживания, продолжающегося в сгенерированном коде, чем реализация Счетных. Диапазон, который, вероятно, кодируется рукой

4
ответ дан 3 December 2019 в 05:14
поделиться

Небольшая разница в выводе Reflector (а также проверка аргументов и дополнительный уровень интернализации здесь определенно не актуальны). Основной код больше похож на:

public static IEnumerable<int> Range(int start, int count) {
    for(int current = 0; current < count; ++current) {
        yield return start + current;
    }
}

То есть вместо другой локальной переменной они применяют дополнительное добавление для каждого yield.

Я попытался протестировать это, но не могу остановить достаточно внешних процессов, чтобы получить понятные результаты. Я также дважды пробовал каждый тест, чтобы игнорировать влияние JIT-компилятора, но даже у него были «интересные» результаты.

Вот пример моих результатов:

Run 0:
time = 4149; result = 405000000450000000
time = 25645; result = 405000000450000000
time = 39229; result = 405000000450000000
time = 29872; result = 405000000450000000

time = 4277; result = 405000000450000000
time = 26878; result = 405000000450000000
time = 26333; result = 405000000450000000
time = 26684; result = 405000000450000000

Run 1:
time = 4063; result = 405000000450000000
time = 22714; result = 405000000450000000
time = 34744; result = 405000000450000000
time = 26954; result = 405000000450000000

time = 4033; result = 405000000450000000
time = 26657; result = 405000000450000000
time = 25855; result = 405000000450000000
time = 25031; result = 405000000450000000

Run 2:
time = 4021; result = 405000000450000000
time = 21815; result = 405000000450000000
time = 34304; result = 405000000450000000
time = 32040; result = 405000000450000000

time = 3993; result = 405000000450000000
time = 24779; result = 405000000450000000
time = 29275; result = 405000000450000000
time = 32254; result = 405000000450000000

и код

using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;

namespace RangeTests
{
  class TestRange
  {
    public static void Main(string[] args)
    {
      for(int l = 1; l <= 2; ++l)
      {
        const int N = 900000000;
        System.GC.Collect(2);
        // for loop
        {
            Stopwatch sw = Stopwatch.StartNew();

            long accumulator = 0;
            for (int i = 1; i <= N; ++i)
            {
                accumulator += i;
            }

            sw.Stop();

            Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, accumulator);
        }
        System.GC.Collect(2);

        //Enumerable.Range
        {
            Stopwatch sw = Stopwatch.StartNew();

            var ret = Enumerable.Range(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);

            sw.Stop();
            Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
        }
        System.GC.Collect(2);

        //self-made IEnumerable<int>
        {
            Stopwatch sw = Stopwatch.StartNew();

            var ret = GetIntRange(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);

            sw.Stop();
            Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
        }
        System.GC.Collect(2);

        //self-made adjusted IEnumerable<int>
        {
            Stopwatch sw = Stopwatch.StartNew();

            var ret = GetRange(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);

            sw.Stop();
            Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
        }
        System.GC.Collect(2);
        Console.WriteLine();
    } }

    private static IEnumerable<int> GetIntRange(int start, int count)
    {
        int end = start + count;

        for (int i = start; i < end; ++i)
        {
            yield return i;
        }
    }

    private static IEnumerable<int> GetRange(int start, int count)
    {
        for (int i = 0; i < count; ++i)
        {
            yield return start + i;
        }
    }
} }

, скомпилированный с помощью

csc.exe -optimize+ -debug- RangeTests.cs
2
ответ дан 3 December 2019 в 05:14
поделиться
Другие вопросы по тегам:

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