Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
2 / 2 / 2
Регистрация: 18.07.2013
Сообщений: 124
1
.NET 4.x

Lock должен блокировать при заполнении - чтение и заполнение, а при чтении ничего

12.06.2018, 02:16. Просмотров 452. Ответов 6
Метки нет (Все метки)

Доброго времени суток, проблема с блокировкой потоков lock.
1й поток в цикле заполняет коллекцию и 3 потока читают, необходимо блокировать 2й, 3й и 4й поток, когда 1 поток добавляет элемент, но в то же время не нужно блокировать потоки при чтении, допустим 3 потока могут читать без блокировок. Проблема в том, что если везде указать lock, то и при чтении будут блокировки, что негативно сказывается на производительности =(
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.06.2018, 02:16
Ответы с готовыми решениями:

Программа вылетает с ошибкой нарушения прав доступа при чтении при заполнении дерева более чем 50 элементами
Приветствую всех. Задание: Для древовидных структур данных предусмотреть вывод характеристик...

При заполнении Edit-а в файл ничего не записывается
Здравствуйте нуждаюсь в помощи.При заполнении едита в файл ничего не сохраняется.в чем может быть...

Автоматическое заполнение данных в поле таблицы при заполнении формы по связанной таблице
Добрый день! Прошу помощи: сама в Access на уровне пользователя, но жизнь заставила.. Суть...

Ошибка при чтении файла: Чтение после конца потока невозможно
Всем добрый вечер! Пытаюсь считать данные из rtf файла и загрузить их в excel файл. Но выпадает...

6
Модератор
Эксперт .NET
5294 / 4089 / 1182
Регистрация: 12.10.2013
Сообщений: 11,895
Записей в блоге: 2
12.06.2018, 04:05 2
KinDer015, посмотрите в сторону использования вот этого класса для блокировки.
1
2 / 2 / 2
Регистрация: 18.07.2013
Сообщений: 124
12.06.2018, 04:28  [ТС] 3
Спасибо за совет, завтра протестирую
0
Эксперт .NET
14487 / 10929 / 2886
Регистрация: 17.09.2011
Сообщений: 18,456
12.06.2018, 08:53 4
Цитата Сообщение от KinDer015 Посмотреть сообщение
но в то же время не нужно блокировать потоки при чтении
Смотря что за коллекция.
Некоторые — очень даже нужно блокировать при чтении.
0
2 / 2 / 2
Регистрация: 18.07.2013
Сообщений: 124
12.06.2018, 20:08  [ТС] 5
SortedDictionary в нем 200к значений, для теста в реальности будет 10-15к (для бинарного поиска по скорости практически не отличается от 200к), мне необходимо изменять около 400 тыс. значений по ключу в сек. и одновременно делать выборку по ключу 600 тыс. раз в секунду (и всего лишь 100-200 добавлений в сек.)

Пытаюсь добиться этой производительности на четырехъядерном процессоре xeon x3440 с помощью многопоточности. (на данный момент лучшая производительность на 16 потоках)

Добавив cacheLock.EnterWriteLock(); в цикл с добавлением новых значений, удалось избавится от краша приложения, за 0,85 сек. потоки читают 600к/сек. и изменяют 400к/сек., по скорости работы на мой взгляд даже очень не плохо, в 3 раза быстрее чем с lock, но немного смущает тот факт, что после 10-30 повторений multithreadSortDic() выводит в консоль "Not found" 1 или 2 раза. Если поставить блокировки везде, то скорость упадет в 3 раза. Может быть просто костыльным методом повторять поиск, если выбило "Not found"? xD Или есть другие способы? (еще не пробовал пул потоков)

немного *овнокода xD
Кликните здесь для просмотра всего текста
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
SortedDictionary<string, string> SortedDic = new SortedDictionary<string, string>();
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
 
private void multithreadSortDic()
        {
            SortedDic.Clear();
            int threadWait = 0;
            bool threadWork = false;
            string t;
            for (int i = 0; i < 200000; i++) 
            {
                t = i.ToString();
                if (!SortedDic.ContainsKey(t))
                {
                    SortedDic.Add(t, t);
                }
            }
 
            Thread[] threads1 = new Thread[8]; // потоки для изменения значений по ключам
            for (int i = 0; i < threads1.Length; i++)
            {
                int threadId = i;
                Thread.Sleep(3);
                threads1[i] = new Thread(delegate ()
                {
                    while (!threadWork) { Thread.Sleep(10); } // ожидание команды для работы потоков
 
                    int iterCount = (400000 / threads1.Count()); // при любом числе потоков кол-во итераций в сумме будет равным 400к
                    int count = 0;
 
                    for (int k = 0; k < iterCount; k++)
                    {
                        string c = count.ToString();
                        if (count >= 99999) { count = 0; }
                        count++;
 
                        SortedDic[c] = "t" + c;
                    }
 
                    threadWait++;
 
                });
                threads1[i].Start();
            }
 
            Thread[] threads2 = new Thread[8]; // потоки для чтения значений по ключам
            for (int i = 0; i < threads2.Length; i++)
            {
 
                int threadId = i;
                Thread.Sleep(3);
                threads2[i] = new Thread(delegate ()
                {
                    while (!threadWork) { Thread.Sleep(10); } // ожидание команды для работы потоков
 
                    float iterCount = (600000 / threads2.Count()); // при любом числе потоков кол-во итераций в сумме будет равным 600к
                    int count = 0;
 
 
                    string result;
                    for (int k = 0; k < iterCount; k++)
                    {
                        if (count >= 99999)
                        {
                            count = 0;
                        }
                        count++;
 
                        if (SortedDic.TryGetValue(count.ToString(), out result))
                        {
 
                        }
                        else
                        {
                            Console.WriteLine("Not found: " + count.ToString());
                        }
 
                    }
 
                    threadWait++;
 
                });
                threads2[i].Start();
            }
 
 
            Thread.Sleep(1000); // ожидание для инициализации потоков
            Console.WriteLine("done");
 
            timerStart(); // запускаем таймер
            threadWork = true; // разрешаем потокам начать работу
 
 
            cacheLock.EnterWriteLock();
            for (int i = 0; i < 50000; i++)  // добавляем 50000 записей, чисто ради теста, в реальности будет 100-200 в секунду
            {
                t = i.ToString();
                SortedDic["y" + t] = t;
               
            }
            cacheLock.ExitWriteLock();
 
 
            while (threadWait < (threads1.Count() + threads2.Count())) { Thread.Sleep(10); } // ожидаем пока потоки выполнят свои циклы записи и чтения
 
            timerStop(1); // останавливаем таймер
            Console.WriteLine(SortedDic.Count);
 
            foreach (var thread in threads1) // убиваем потоки записи
            {
                thread.Abort(); 
            }
            foreach (var thread in threads2) // убиваем потоки чтения
            {
                thread.Abort();
            }
            multithreadSortDic(); // для длительного тестирования запускаем повторно
        }


Добавлено через 7 минут
Еще есть предположение, что если заблокировать не только запись для других потоков но и чтение в момент добавления, то данная проблема исчезнет, но в этом случае выбивает исключение.

C#
1
2
3
4
5
6
7
8
9
10
 
            cacheLock.EnterReadLock();
            cacheLock.EnterWriteLock();
            for (int i = 0; i < 50000; i++)  
            {
                t = i.ToString();
                SortedDic["y" + t] = t;            
            }
            cacheLock.ExitReadLock();
            cacheLock.ExitWriteLock();
0
Эксперт .NET
14487 / 10929 / 2886
Регистрация: 17.09.2011
Сообщений: 18,456
12.06.2018, 20:14 6
Цитата Сообщение от KinDer015 Посмотреть сообщение
Добавив cacheLock.EnterWriteLock(); в цикл с добавлением новых значений
А где же синхронизация в потоках?

Цитата Сообщение от KinDer015 Посмотреть сообщение
Еще есть предположение, что если заблокировать не только запись для других потоков но и чтение в момент добавления
Почитайте документацию к этому классу — что конкретно могут делать потоки при каком замыкании.
Сразу поймете, почему выбивает.
0
2 / 2 / 2
Регистрация: 18.07.2013
Сообщений: 124
13.06.2018, 08:44  [ТС] 7
В общем я бегло посмотрел документацию, сейчас внимательно прочитаю, не совсем понял, что подразумевается под синхронизацией в потоках

Добавлено через 6 часов 35 минут
Добавил блокировку через отдельную функцию, как в документации, которая дает доступ только одному потоку, а чтение разрешает всем. Все работает как нужно без исключений, но к сожалению время возросло до 2 сек. Разбивать коллекцию на равные части для потоков не даст большей производительности, так как у нас бинарный поиск. В итоге данное приложение должно быть заточено под 12-и ядерный сервер, где довольно низкая производительность на ядро. Как я понимаю бинарный поиск на такой машине будет проигрывать некоторым другим методам сортировки и выборки, которые подойдут для многопоточности, но вот какие стоит использовать не знаю.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.06.2018, 08:44

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

"Нарушение прав доступа при чтении по адресу" при чтении структур из бинарного файла
Пытаюсь разобраться со структурами в бинарных файлах. Допустим, есть массив структур. Записываю...

При чтении dll библиотеки в обычном(не бинарном) виде, чтение прерывается на NULL
Задача такая: открыть dll файл(не мой) в обычном текстовом виде(каким его могут открыть обычные...

При нажатии на клавиши Num Lock, Caps Lock, Insert вывести в StatusBar состояние кнопок C++
Добрый день, уважаемые программисты, студенты, школьники, а также все посетители этого...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.