/**
* 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();
}
Почему должен 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; } }
}
}
Мое предположение - то, что Вы работаете в отладчике. Вот мои результаты, создав из командной строки с "/o +/debug-"
time = 142; result = 987459712
time = 1590; result = 987459712
time = 1792; result = 987459712
Существуют все еще незначительные различия, но это как не объявлено. Внедрения блока итератора не вполне так же эффективны как нестандартное решение, но они довольно хороши.
Принятие этого является выполнением сборки конечных версий, иначе все сравнения прочь, поскольку JIT не будет выкладываться полностью.
Вы могли посмотреть на блок с отражателем и видеть то, что оператор 'урожая' расширяется также. Компилятор будет создавать класс для инкапсуляции итератора. Возможно, существует больше обслуживания, продолжающегося в сгенерированном коде, чем реализация Счетных. Диапазон, который, вероятно, кодируется рукой
Небольшая разница в выводе 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