Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Максимальный размер ConcurrentDictionary в 32-битных приложениях / 25 сообщений из 196, страница 1 из 8
26.05.2016, 13:18
    #39244003
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Делаю так:

Код: c#
1.
2.
3.
4.
5.
6.
public static ConcurrentDictionary<int, bool> Tested;

Tested = new ConcurrentDictionary<int, bool>(_threadsQty, mmax - mmin + 1);

for (int i = mmin; i <= mmax; i++) // добавляем записи с начальным значением false
    Tested.TryAdd(i, false);



Пока количество элементов = 2^24, всё работает. При 2^25 ловлю System.OutOfMemoryException.

Если же звать конструктор без параметров
Tested = new ConcurrentDictionary<int, bool>();

то Exception не ловится, а просто приложение "stop working".

В обоих случаях всё происходит в момент выделения процессу памяти ~1400000 кб.

Вопрос.
Есть ли ограничения на максимальное кол-во записей в ConcurrentDictionary, либо на размер выделенной под него памяти?
Либо имеет значение только общий размер памяти, выделенной 32-битному процессу?
...
Рейтинг: 0 / 0
26.05.2016, 13:34
    #39244018
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Небольшое уточнение: Exception ловится в момент заполнения словаря, после работы конструктора.
...
Рейтинг: 0 / 0
26.05.2016, 13:41
    #39244022
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Это проблема 32-битного процесса. Всего 4 Гб из них 2 Гб ОС, вторые 2 Гб проге, в них и .Net и твои данные.

В твоем случае лучше BitArray взять. Тут будет 1 бит - одно значение, т.е. все положительные значения Int32 (до 2^31) займут 256 Мб (2^28)
...
Рейтинг: 0 / 0
26.05.2016, 13:51
    #39244036
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Я бы взял BitArray, но он не потокобезопасен. В моём случае без вариантов подходит только что-то из System.Collections.Concurrent

Самое забавное в моей истории, что на 32-битной Windows 7 с 4 Гб ОЗУ иногда эта программа проходит описанную инициализацию и начинает работать, а на 64-битной Windows Server c большим количеством памяти устойчиво падает вышеописанным образом.
...
Рейтинг: 0 / 0
26.05.2016, 14:02
    #39244051
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®Я бы взял BitArray, но он не потокобезопасен.
Используй блокировки lock() . Быстрее будет чем с ConcurrentDictionary
...
Рейтинг: 0 / 0
26.05.2016, 14:07
    #39244057
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Если еще быстрее надо, то взять массив Int32[], прописать логику работы с битами, а для чтения/записи использовать Interlocked функции.
...
Рейтинг: 0 / 0
26.05.2016, 14:48
    #39244103
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Пока в порядке эксперимента переписал всё под BitArray, работает правильно как с ConcurrentDictionary без принятия специальных мер по блокировке. Что очень интересно, если вспомнить что с обычным массивом (в самой первоначальной версии программы) были чудеса.
...
Рейтинг: 0 / 0
26.05.2016, 14:52
    #39244107
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®работает правильно как с ConcurrentDictionary без принятия специальных мер по блокировке.
Это твое "правильно" те еще грабли. Когда проблемы возникнут - исключений не будет, просто получишь неправильный результат своего расчета.
...
Рейтинг: 0 / 0
26.05.2016, 15:01
    #39244121
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima T,

ну, если задача чисто заполнить справочник и он уверен в том, что пересечений из разных потоков не будет, то по сути всё отработает без ошибок. Но это же бессмысленный пример в вакууме :) одним заполнением то, он не ограничится (наверное)
...
Рейтинг: 0 / 0
26.05.2016, 15:21
    #39244146
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Т.к. работа с битами происходит через байты, то вполне возможна такая ситуация когда два потока одномоментно захотят установить разные биты в одном байте.
Например это может произойти так
Поток 1Поток 2Прочитал байтПрочитал байтУстановил бит 3Установил бит 5Записал байтЗаписал байт
в итоге то что сделал Поток 1 будет затерто, т.е. бит 3 не будет установлен.
Поэтому блокировки доступа при записи обязательны. При чтении можно не блокировать доступ, но тогда перед записью, внутри блокировки делать повторное чтение.
...
Рейтинг: 0 / 0
26.05.2016, 15:22
    #39244148
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima TЭто твое "правильно" те еще грабли.

Всецело догадываюсь об этом и обещаю заблаговременно принять меры :)
А пока факт остаётся фактом: BitArray работает правильно там, где bool[] вынудил прибегнуть к ConcurrentDictionary, при числе потоков от 4 до 32.

Прироста скорости по сравнению с ConcurrentDictionary пока не обнаружил.
...
Рейтинг: 0 / 0
26.05.2016, 15:35
    #39244164
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®bool[] вынудил прибегнуть к ConcurrentDictionary, при числе потоков от 4 до 32.
bool[] ничем не отличается от BitArray, разве что в 8 раз больше места требуется.
AR®Прироста скорости по сравнению с ConcurrentDictionary пока не обнаружил.
Можно не заметить если на работу с массивом уходит незначительная часть времени работы проги. Например если это 1%, то даже если в 10 раз ускорилось, то ускорение всего 0,9% от общего времени.
...
Рейтинг: 0 / 0
26.05.2016, 16:03
    #39244196
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima Tbool[] ничем не отличается от BitArray, разве что в 8 раз больше места требуется.
Был бы готов согласиться, но эксперимент выявил обратное.

Dima TМожно не заметить если на работу с массивом уходит незначительная часть времени работы
Вполне допускаю. Примерно так оно в этой программе и есть.

Огорчает другое: при 2^25 элементов процесс запустился, а при 2^26 - уже нет.
Буду думать...
...
Рейтинг: 0 / 0
26.05.2016, 16:11
    #39244203
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Похоже, теперь дохнет уже на выделении памяти объектам в каждом потоке.
...
Рейтинг: 0 / 0
26.05.2016, 17:35
    #39244257
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima T

Благодарю за "наводку" на класс BitArray.

Скажите, будет ли в общем случае достаточно брать в lock(){ } операции записи в массив?
...
Рейтинг: 0 / 0
26.05.2016, 18:02
    #39244285
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®Скажите, будет ли в общем случае достаточно брать в lock(){ } операции записи в массив?
Думаю да, но на 100% не уверен.

Лучше все обращения обернуть. Сделай класс-обертку, два метода Read() и Write(). В них пропиши c lock(). Как понял на общем времени работы твоего кода это особо не скажется, но надежность будет гарантированная.
...
Рейтинг: 0 / 0
27.05.2016, 08:02
    #39244487
Ilya81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
По крайней мере размер требуемой памяти в этом случае оцинеть не сложно, так что рекомендую использовать MemoryFailPoint и ловить InsufficientMemoryException.
...
Рейтинг: 0 / 0
27.05.2016, 08:41
    #39244514
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®Скажите, будет ли в общем случае достаточно брать в lock(){ } операции записи в массив?
Посмотрел исходник bitarray.cs
Чтение
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
        public bool Get(int index) {
            if (index < 0 || index >= Length) {
                throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
            }
            Contract.EndContractBlock();
    
            return (m_array[index / 32] & (1 << (index % 32))) != 0;
        }


Думаю без lock() можно читать. Нечему тут глючить при многопоточности.
...
Рейтинг: 0 / 0
27.05.2016, 12:56
    #39244811
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Предварительный диагноз такой: с BitArray немного быстрее, чем с ConcurrentDictionary, но только пока не использую lock(){}.
С lock остаётся только преимущество в памяти (что для моего случая важно). Видимо потому, что блокировка накладывается на весь массив, а не на отдельный бит :)

Интересно, а можно ли скомпилировать 64-битное приложение на 32-битном компе?
...
Рейтинг: 0 / 0
27.05.2016, 13:10
    #39244834
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®С lock остаётся только преимущество в памяти (что для моего случая важно). Видимо потому, что блокировка накладывается на весь массив, а не на отдельный бит :)
Блокировка вообще не накладывается. Это просто флаг, первый поток установил и что-то делает, второй, при попытке его установить - останавливается и ждет пока первый не снимет.

Можешь разделить массив на условные блоки (0-1048575, 1048576-... и т.д.) и использовать отдельный объект для блокировки каждого блока. Только учти что блоки массива, за который отвечает одна блокировка, должны быть кратны 32. Т.к. внутри BitArray используется Int32[].

AR®Интересно, а можно ли скомпилировать 64-битное приложение на 32-битном компе?
Скомпилировать можно, но оно не запустится.
...
Рейтинг: 0 / 0
27.05.2016, 13:46
    #39244873
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima TСкомпилировать можно, но оно не запустится.
Не запустится на компьютере компиляции - это устраивает.
Хотелось бы, чтобы оно запустилось на 64-битной ОС, где памяти стоит побольше, и не будет ограничения как для 32-битного процесса.
Никогда не делал так, потому спрашиваю.
...
Рейтинг: 0 / 0
27.05.2016, 14:38
    #39244930
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®С lock остаётся только преимущество в памяти (что для моего случая важно). Видимо потому, что блокировка накладывается на весь массив, а не на отдельный бит :)
Можно Interlocked.CompareExchange() вместо lock(). Так вообще без блокировок. Только класс придется свой делать.
class ConcurrentBitArrayСкопипастил из BitArray только минимально нужное.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
		public sealed class ConcurrentBitArray {
			Int32[] m_array;

			public ConcurrentBitArray(int length) {
				m_array = new Int32[(length - 1) / 32 + 1];
			}

			public bool this[int index] {
				get {return Get(index); }
				set {Set(index,value); }
			}

			public bool Get(int index) {
				return (m_array[index / 32] & (1 << (index % 32))) != 0;
			}

			public void Set(int index, bool value) {
				Int32 cur, val;
				do {
					cur = m_array[index / 32];
					if (value) {
						val = cur | (1 << (index % 32));
					} else {
						val = cur & ~(1 << (index % 32));
					}
				} while (cur != Interlocked.CompareExchange(ref m_array[index / 32], val, cur));
			}
		}


		static void Main(string[] args) {
			var b = new ConcurrentBitArray(1000);
			Console.WriteLine(b[100]);
			b[100] = true;
			Console.WriteLine(b[100]);
			b[200] = true;
			Console.WriteLine(b[200]);
			b[200] = false;
			Console.WriteLine(b[200]);
			return;
		}


AR®Хотелось бы, чтобы оно запустилось на 64-битной ОС, где памяти стоит побольше, и не будет ограничения как для 32-битного процесса.
Если по-простому: Внутри EXE находится IL-код, по месту запуска он может заработать и как х32 и как x64 без перекомпиляций. Можно явно задать чтобы везде одинаково было. Это в заголовке EXE указывается. Подробно у Рихтера расписано.
Как в студии настроить не знаю, а с командной строки так компилировать
Код: c#
1.
%windir%\Microsoft.NET\Framework\v4.0.30319\csc /o /out:MyProg.exe  program.cs


без указания платформы, тогда на x32 компе запустится как x32, на x64 как x64

Только не надейся что при x64 у тебя не выскочит OutOfMemory. Там тоже ограничения есть, виндовс как-то ограничивает чтобы приложение всю память не отъело.
И еще такой момент: x64 работает на ~30% медленнее чем х32.
...
Рейтинг: 0 / 0
27.05.2016, 14:56
    #39244949
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Спасибо за класс.
Dima TТолько не надейся что при x64 у тебя не выскочит OutOfMemory. Там тоже ограничения есть, виндовс как-то ограничивает чтобы приложение всю память не отъело.


Очень интересно, каковы они и где установливаются. Работает же как-то, ну например, SQL Server, который берёт, сколько ему нужно.


Dima TИ еще такой момент: x64 работает на ~30% медленнее чем х32.

Это с лихвой компенсировалось бы отсутствием ограничений на выделяемую процессу память. В процессе экспериментов я попутно выяснил, что, например, BitArray даёт время работы раза ~в 4 больше, чем bool[ ] (он используется у меня в каждом отдельном потоке).

И вот ещё интересный вопрос. Если делать свой класс, как ваш ConcurrentBitArray, с точки зрения минимизации времени работы, что лучше взять за основу: Int32, или более короткие Int16, byte, или наоборот, длинный Int64 ?
...
Рейтинг: 0 / 0
27.05.2016, 15:18
    #39244984
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
AR®Спасибо за класс.
Dima TТолько не надейся что при x64 у тебя не выскочит OutOfMemory. Там тоже ограничения есть, виндовс как-то ограничивает чтобы приложение всю память не отъело.


Очень интересно, каковы они и где установливаются. Работает же как-то, ну например, SQL Server, который берёт, сколько ему нужно.
Специально не интересовался, случайно нигде не попадалось, так что гугл в помощь если интересно. Наверно есть какое-нибудь WinAPI чтобы попросить ОС дать больше чем по умолчанию.
AR®Dima TИ еще такой момент: x64 работает на ~30% медленнее чем х32.
Это с лихвой компенсировалось бы отсутствием ограничений на выделяемую процессу память. В процессе экспериментов я попутно выяснил, что, например, BitArray даёт время работы раза ~в 4 больше, чем bool[ ] (он используется у меня в каждом отдельном потоке).
bool[ ] быстрее, т.к. там просто получение байта из массива (m_array[index]), без всяких доп.расчетов (m_array[index / 32] & (1 << (index % 32)))
AR®И вот ещё интересный вопрос. Если делать свой класс, как ваш ConcurrentBitArray, с точки зрения минимизации времени работы, что лучше взять за основу: Int32, или более короткие Int16, byte, или наоборот, длинный Int64 ?
Int16 и byte отпадают Interlocked.CompareExchange() перегружен только для Int32 и Int64. Работа с Int64 под x32 медленнее. В принципе можешь затестить как оно будет в твоей задаче.
...
Рейтинг: 0 / 0
27.05.2016, 15:44
    #39245021
AR®
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Максимальный размер ConcurrentDictionary в 32-битных приложениях
Dima TInt16 и byte отпадают Interlocked.CompareExchange() перегружен только для Int32 и Int64

Я имел ввиду, что если городить совсем свой огород и не закладываться на использование Interlocked, в каком случае обращение к требуемому биту будет быстрее: с byte, Int16, Int32, Int64?
И ещё: byte и Int16 будут занимать в памяти в случае большого массива из них действительно байт и 2 соответственно?
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Максимальный размер ConcurrentDictionary в 32-битных приложениях / 25 сообщений из 196, страница 1 из 8
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]