Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.98/43: Рейтинг темы: голосов - 43, средняя оценка - 4.98
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676

Ботлнек String/StringBuilder

22.11.2020, 08:42. Показов 11631. Ответов 220
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
обсуждение, начавшееся в другой теме переношу сюда. Самой тяжёлой является операция:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
string source = File.ReadAllText(@"d:\work\words\source.txt", Encoding.GetEncoding(1251));
var sb_source = new StringBuilder(source, Source.Length);
Dictionary<string, int> F = new Dictionary<string, int>();
// ---
// тут вставляем код заполнения F, у меня получается около 70000 пар
// заполнение происходит очень быстро
// ---
foreach (var elem in F)
{
    // а вот тут был string и работало это, как мы все понимаем 200 лет
    // теперь тут StringBuilder, работает быстрее, но не слишком
    // можно сделать Parallels.ForEach, для моего i5 ускорится в ~4 раза
    sb_source = sb_source.Replace(elem.Key, "\0\0\0");
};
Нолики "\0" - это классификатор отсутствия информации, то есть после нескольких итераций на выходе будет файл полностью забитый нулями. Это один из показателей верности работы алгоритма.
Получается для файла в 4 мб (гигабайты я пока использовать не стал) это 4*70000=280000 Мбайт чтения и поменьше записи в памяти. Возможно стоит перевести на массив byte[] или ulong[] и делать замену вручную.

Добавлено через 10 минут
Цитата Сообщение от belalugoci Посмотреть сообщение
можно сделать Parallels.ForEach, для моего i5 ускорится в ~4 раза
StringBuilder также не является потокобезопасным, поэтому его работа с параллельными потоками недопустима.
Видимо нельзя
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.11.2020, 08:42
Ответы с готовыми решениями:

List<string, string, string> есть ли в C# что-то подобное?
Мне надо добавить в List не только имя файла, но и некоторые строки из этого файла. Т.е. например, у меня есть в определенном директории...

StringBuilder и регулярки
Подскажите, можно ли на StringBuilder использовать RegEx.Replace? Если да, то как?

Подскажите как дешифровать текст с использованием StringBuilder
Дана строка, содержащая зашифрованный русский текст. Каждая буква заменяется на следующую за ней (буква я заменяется на а). Получить новую...

220
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
10.12.2020, 18:21  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
До этого на ассемблере, С, С++ и массе других языком всё тоже самое реализовывали без словарей.
Словарь сильно упрощает создание кода
читаю периодически чужой код на C/C++ для разных алгоритмов, да те же BTW, RLE, MTF и т.п. - и наслаждаюсь как человеки умеют.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
10.12.2020, 18:52
Цитата Сообщение от belalugoci Посмотреть сообщение
читаю периодически чужой код на C/C++ для разных алгоритмов, да те же BTW, RLE, MTF и т.п. - и наслаждаюсь как человеки умеют.
Поэтому и существую разные языки.
Если вам нужно быстрое создание кода, потенциально многоплатформенного - используете C#.
Если нужен максимально быстрый и компактный код то С, С++, Ассемблер.

Многие приёмы из С/С++ можно использовать и в C#.
Но возникает вопрос, а зачем тогда вообще использовать C# если не используются его "вкусняшки"?
Лучше тогда сразу работать в плюсах.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
11.12.2020, 05:11  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Поэтому и существую разные языки.
не совсем поэтому, но спорить не буду.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Лучше тогда сразу работать в плюсах.
когда я сидел на Turbo C, потом Borland C++, то это было весьма неудобно в ряде аспектов, а потом вышел Delphi, и пре всей моей нелюбви к синтаксису и приемам работы в Pascal, я перешёл на него. C/C++ просто забыт напрочь за исключением каких-то простых вещей. Поэтому совмещать 2-3-5 языков и решать задачу в зависимости от потребностей там или там - это не мой вариант.
Я с пару лет назад брался за Python, нравятся многие вещи, но там всё плохо с производительностью, нет нормальной реализации GUI, во всяком случае в 2018 году не было. Поэтому C# выбран как хорошо документированный и как баланс между скоростью разработки и производительностью. Поэтому лучше в C# запихать кусочек из C-подобного, чем переходить на С в целом.
0
178 / 33 / 17
Регистрация: 02.02.2014
Сообщений: 373
11.12.2020, 05:40
Цитата Сообщение от belalugoci Посмотреть сообщение
когда я сидел на Turbo C, потом Borland C++, то это было весьма неудобно в ряде аспектов, а потом вышел Delphi, и пре всей моей нелюбви к синтаксису и приемам работы в Pascal, я перешёл на него. C/C++ просто забыт напрочь за исключением каких-то простых вещей. Поэтому совмещать 2-3-5 языков и решать задачу в зависимости от потребностей там или там - это не мой вариант.
Я с пару лет назад брался за Python, нравятся многие вещи, но там всё плохо с производительностью, нет нормальной реализации GUI, во всяком случае в 2018 году не было. Поэтому C# выбран как хорошо документированный и как баланс между скоростью разработки и производительностью. Поэтому лучше в C# запихать кусочек из C-подобного, чем переходить на С в целом.
А почему не рассматриваете возможность писать сразу на нескольких языках? Например, в вашем случае хорошо подойдет связка C++ CLI/C#.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
11.12.2020, 06:17  [ТС]
Цитата Сообщение от VBDUnit Посмотреть сообщение
А почему не рассматриваете возможность писать сразу на нескольких языках?
у меня проблемы с памятью, я трачу 90% времени на перепрочтение MSDN, тем на форуме и старых своих исходников чтобы вспомнить как всё это работает. Тем более для меня программирование находится в зоне нечастого хобби, я могу не садиться за VS по году, а когда возвращаюсь, то я как чистый лист. Время запоминания прочитанного где-то 2-3 дня, я просто не успею за такое время погрузиться и в C и в C#. По-хорошему нужно иметь хорошего товарища-кодера, который легко воплощает идеи в коде. Но таких товарищей найти сложно, деньги портят людей - проверено на практике.
0
178 / 33 / 17
Регистрация: 02.02.2014
Сообщений: 373
11.12.2020, 13:01
Просто нюанс в том, что в рамках хобби вы сейчас, по сути, погрузились в задачи, сложность которых уже требует большего, чем хобби, вовлечения, времени и компетенций. Тут либо обратно, "всплывать на поверхность" (например, отказаться от оптимизации и пока только работать над алгоритмами, не уделяя внимание скорости), либо уделять больше временных и умственных ресурсов, либо, как вы упомянули, делегировать узкие задачи специалистам, но тогда встаёт вопрос о мотивации людей - а это тоже целая отдельная тема. И деньги здесь лишь один из инструментов, который можно применять, а можно не применять. Любой инструмент можно применять с разной степенью эффективности, в том числе, отрицательной.
1
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
11.12.2020, 14:36  [ТС]
Цитата Сообщение от VBDUnit Посмотреть сообщение
вы сейчас, по сути, погрузились в задачи, сложность которых уже требует большего, чем хобби
в поиске решения находится эта граница.

Цитата Сообщение от VBDUnit Посмотреть сообщение
отказаться от оптимизации и пока только работать над алгоритмами, не уделяя внимание скорости
ну в некотором роде оптимизация - это инициатива форумчан, игра умов, я, всё что мы обсуждаем, считаю StringBuilder'ом без проблем. Если бы вы с Элд Хасп не помогли с последними рекомендациями - я бы остался на той самой границе. Дело в том что эта часть расчётов является только инструментом для получения данных, которые уходят дальше в другую программу и по сути она нужна только один раз (повторно в основном использую если нужно что-то проверять с другими данными).

Цитата Сообщение от VBDUnit Посмотреть сообщение
но тогда встаёт вопрос о мотивации людей - а это тоже целая отдельная тема
Я не могу ничего предложить кроме интереса в решении. Если интереса нет никакого, то тема остается сугубо в рамках моего решения, если такое имеется, если нет, то я многие вещи делаю вручную.

Цитата Сообщение от VBDUnit Посмотреть сообщение
Любой инструмент можно применять с разной степенью эффективности, в том числе, отрицательной.
я еще пользуюсь Excel, PowerShell, awk, отрицательной эффективность не может быть просто потому, что я не пишу через классы решение 2+2, я пользуюсь калькулятором для этого - для каждой задачи свой инструмент.

Я понимаю вашу мысль, но и у меня есть своё мнение на этот счет.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
11.12.2020, 16:19
Цитата Сообщение от belalugoci Посмотреть сообщение
не совсем поэтому, но спорить не буду.
Да, конечно это не единственная причина, а одна из.
0
178 / 33 / 17
Регистрация: 02.02.2014
Сообщений: 373
14.12.2020, 11:42
Собственно, последний вариант с минимизированным числом поисков:
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
 
namespace ConsoleApp5
{
    class Program
    {
        static void Main(string[] args)
        {
            //Читаем имя файла
            var fileName = Console.ReadLine();
 
            //Читаем текст
            var text = File.ReadAllBytes(fileName.Trim('\"'));
 
            //Максимальное число разных значений, которое может принять байт
            int maxDifferentByteCount = 256;
            //Например, если у нас только строчные латинские буквы + пробел, то
            //Это будет не 256, а 23
 
            //Словари, у которых ключ - это строка
            //Любят постоянно считать хэши строк. Не всегда, но любят.
            //Для того, чтобы ускорить всё, сделаем пару штук:
            //1) Хэш считаем самостоятельно
            //2) Для расчёта хэша не создаем новые строки - работаем напрямую с памятью
            //3) При ключе long хэш всё равно будет досчитываться, но для long он уже довольно быстрый
 
            //Короче, алгоритм хранит не частоту подстрок
            //а частоту хэшей этих подстрок
            var frequencyDicitonary = new Dictionary<int, hashInfo>();
 
 
            var st = new Stopwatch();
            st.Reset();
            st.Start();
            //Заполняем словари
            FillFrequences(text, 1, 8, frequencyDicitonary, maxDifferentByteCount);
            st.Stop();
 
            //Находим самый частый хэш
            var maxFqKeyValue = FindMax(frequencyDicitonary, a => a.Value.RepeatCount);
            var maxFqHash = maxFqKeyValue.Key;
 
 
            //Выводим
            var foundBytes = text[maxFqKeyValue.Value.StartPosition..maxFqKeyValue.Value.EndPosition];
            var foundBytesText = foundBytes.Length + " байт: " + string.Join(", ", foundBytes.ToList().ConvertAll(a => a.ToString()));
 
            Console.WriteLine($"{maxFqKeyValue.Value.RepeatCount} повторений фрагмента {foundBytesText}");
            Console.WriteLine($"Обработка длилась {st.ElapsedMilliseconds} мс");
            Console.ReadLine();
        }
        static T FindMax<T>(IEnumerable<T> collection, Func<T, int> num)
        {
            var n = int.MinValue;
            T lastResult = default(T);
            foreach (var item in collection)
            {
                var newN = num(item);
                if (newN > n)
                {
                    newN = n;
                    lastResult = item;
                }
            }
            return lastResult;
        }
        static long[] power31Table; //Табличка степеней 31, интерпретированных как long
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static unsafe int FastHash(void* begin, int byteCount, long* power31Ptr)
        {
            //Быстрый хэш, не требующий создания новой подстроки. Работает на фрагменте памяти
            long hashedValue = 0;
            unchecked
            {
                //Считаем сразу по 4 символа за раз, интерпретируя их как long
                var longCount = byteCount / sizeof(long);
                var tail = byteCount % sizeof(long);
                long* ptr = (long*)begin;
                long* end = ptr + longCount;
                //hashedValue += (long)byteCount * *power31Ptr++;
                //i++;
 
                while (ptr < end)
                {
                    hashedValue += *ptr * *power31Ptr++;
                    ptr++;
                }
 
 
                //Досчитываем хвостик
                byte* tailEnd = (byte*)begin + byteCount;
                byte* tailPtr = tailEnd - tail;
                while (tailPtr < tailEnd)
                {
                    hashedValue += *tailPtr * *power31Ptr++;
                    tailPtr++;
                }
            }
            return (int)hashedValue ^ (int)(hashedValue >> 32);
        }
        //Заполнение таблицы степеней
        static void BuildPower31TableIfNeed(int maxByteCount)
        {
            //Число итераций хэш функции
            var maxHashIterationCount = maxByteCount / sizeof(long) + maxByteCount % sizeof(long) + 1;
 
            //Если таблица ещё не создана или она меньше, чем нам надо
            if (power31Table == null || power31Table.Length < maxHashIterationCount)
            {
                //Создаём новый экземпляр таблицы в отдельной переменной
                var newPower31Table = new long[maxHashIterationCount * 2];
                unsafe
                {
                    //заполняем
                    for (int i = 0; i < newPower31Table.Length; i++)
                    {
                        var v = Math.Pow(31, i);
                        newPower31Table[i] = *(long*)&v;
                    }
                }
                //и только потом приравниваем статическую переменную к нашей новой таблице
                power31Table = newPower31Table;
                //это делает данный метод потокобезопасным без блокировок
                //максимум, что может случится - лишний раз просчитается таблица
            }
        }
 
 
        class hashInfo
        {
            public int StartPosition;
            public int Length;
            public int EndPosition => StartPosition + Length - 1;
            public int RepeatCount;
 
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void SnapshotAndIncrement(byte* dataBegin, byte* fragmentBegin, int byteCount)
            {
                StartPosition = (int)(fragmentBegin - dataBegin);
                Length = byteCount;
                RepeatCount++;
            }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public void Increment()
            {
                RepeatCount++;
            }
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static unsafe void AddOrIncHash(Dictionary<int, hashInfo> outputDictionary, int hash, byte* dataBegin, byte* fragmentBegin, int byteCount)
        {
            if (outputDictionary.TryGetValue(hash, out var hi))
                hi.Increment();
            else
            {
                hi = new hashInfo();
                hi.SnapshotAndIncrement(dataBegin, fragmentBegin, byteCount);
            }
        }
 
        static void FillFrequences(byte[] text, int minLength, int maxLength, Dictionary<int, hashInfo> outputDictionary, int maxDifferentByteCount = 256)
        {
            BuildPower31TableIfNeed(maxLength * sizeof(byte));
            outputDictionary.Clear();
            int[] hashCounts = new int[256 * 256 * 256];
            unsafe
            {
                //Получаем прямой доступ к памяти
                fixed (byte* textPtrBegin = text)
                {
                    if (minLength <= 1)
                    {
                        core1(text, outputDictionary, textPtrBegin, maxDifferentByteCount);
                        Console.WriteLine("Длина 1 байт обработана");
                        minLength++;
                    }
                    if (minLength <= 2 && maxLength >= 2)
                    {
                        core2(text, outputDictionary, textPtrBegin, maxDifferentByteCount);
                        Console.WriteLine("Длина 2 байт обработана");
                        minLength++;
                    }
                    if (minLength <= 3 && maxLength >= 3)
                    {
                        core3(text, outputDictionary, textPtrBegin, hashCounts, maxDifferentByteCount);
                        Console.WriteLine("Длина 3 байт обработана");
                        minLength++;
                    }
                    if (minLength <= 4 && maxLength >= 4)
                    {
                        core4(text, outputDictionary, textPtrBegin);
                        Console.WriteLine("Длина 4 байт обработана");
                        minLength++;
                    }
                    for (int n = 5; n <= 7; n++)
                        if (minLength <= n && maxLength >= n)
                        {
                            core567(text, outputDictionary, textPtrBegin, n);
                            Console.WriteLine($"Длина {n} байт обработана");
                            minLength++;
                        }
                    //Внешний цикл - перебор всех искомых длинн
                    for (int len = minLength; len <= maxLength; len++)
                    {
                        coreUniversal(text, outputDictionary, textPtrBegin, len);
                        Console.WriteLine($"Длина {len} байт обработана");
                    }
                }
            }
        }
        private static unsafe void core1(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin, int maxDifferentByteCount)
        {
            var len = 1;
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
            int msk = 0b1010011110010001001110001001010;
 
            var byteCount = len;
            for (int i = 0; i < 256; i++)
            {
                outputDictionary[i ^ msk] = new hashInfo();
            }
            int* countOf = stackalloc int[256];
            int strSetCount = 0;
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var index = *ptr;// FastHash(ptr, byteCount);
                //Увеличиваем счетчик
                countOf[index]++;
 
                if (countOf[index] == 1)
                {
                    var hash = index ^ msk;
                    //Запоминаем строку чтобы восстановить из хэша
                    var item = outputDictionary[hash];
                    item.SnapshotAndIncrement(begin, ptr, len);
                    strSetCount++;
                    if (strSetCount >= maxDifferentByteCount)
                        break;
                }
 
                //Следующий символ
                ptr++;
            }
 
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var index = *ptr;// FastHash(ptr, byteCount);
 
                //Увеличиваем счетчик
                countOf[index]++;
                //Следующий символ
                ptr++;
            }
            for (int i = 0; i < 256; i++)
                outputDictionary[i ^ msk].RepeatCount = countOf[i];
        }
        private static unsafe void core2(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin, int maxDifferentByteCount)
        {
            var len = 2;
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
 
            var byteCount = len;
            for (int i = ushort.MinValue; i <= ushort.MaxValue; i++)
            {
                if (i < 256)
                    outputDictionary[~i] = new hashInfo();
                else
                    outputDictionary[i] = new hashInfo();
            }
 
            int* countOf = stackalloc int[ushort.MaxValue + 1];
            int maxDifPow2 = maxDifferentByteCount * maxDifferentByteCount;
 
            int strSetCount = 0;
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                int index = *(ushort*)ptr;// FastHash(ptr, byteCount);
 
                //Увеличиваем счетчик
                countOf[index]++;
                if (countOf[index] == 1)
                {
                    int hash = index;
                    if (hash < 256)
                        hash = ~hash;
 
                    //Запоминаем строку чтобы восстановить из хэша
                    //AddHashString(hash, begin, ptr, len, stringByHashDictionary);
                    outputDictionary[hash].SnapshotAndIncrement(begin, ptr, len);
 
                    //strSet[hash] = true;
                    strSetCount++;
                    if (strSetCount >= maxDifPow2)
                        break;
                }
                //Следующий символ
                ptr++;
            }
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                int index = *(ushort*)ptr;// FastHash(ptr, byteCount);
 
                //Увеличиваем счетчик
                countOf[index]++;
 
                //Следующий символ
                ptr++;
            }
            for (int i = ushort.MinValue; i <= ushort.MaxValue; i++)
            {
                int hash = i;
                if (hash < 256)
                    hash = ~hash;
                outputDictionary[hash].RepeatCount = countOf[i];
            }
        }
        private static unsafe void core3(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin, int[] hashCounts, int maxDifferentByteCount)
        {
            var len = 3;
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
 
            var byteCount = len;
 
            int setCount = 0;
            Array.Clear(hashCounts, 0, hashCounts.Length);
            int maxSetCount = maxDifferentByteCount * maxDifferentByteCount * maxDifferentByteCount;
 
            uint maxIndex = 0;
 
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var index = (uint)*(ushort*)ptr;
                index *= 256;
                index += *(ptr + 2);
 
 
                hashCounts[index]++;
 
                if (hashCounts[index] == 1)
                {
                    var hash = (int)index;
                    if (hash <= ushort.MaxValue)
                        hash = ~hash;
 
                    maxIndex = Math.Max(maxIndex, index);
                    hashCounts[index]++;
                    //Запоминаем строку чтобы восстановить из хэша
                    //AddHashString((int)hash, begin, ptr, len, stringByHashDictionary);
                    var hi = new hashInfo();
                    hi.SnapshotAndIncrement(begin, ptr, len);
                    outputDictionary[hash] = hi;
                    setCount++;
                    if (setCount >= maxSetCount)
                        break;
                }
 
                //Следующий символ
                ptr++;
            }
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var index = (uint)*(ushort*)ptr;
                index *= 256;
                index += *(ptr + 2);
                hashCounts[index]++;
                //Следующий символ
                ptr++;
            }
            if (maxIndex > int.MaxValue)
                maxIndex = int.MaxValue;
 
            for (int i = 0; i < maxIndex; i++)
            {
                var hashCount = hashCounts[i];
                if (hashCount > 0)
                {
                    var hash = i;
                    if (hash <= ushort.MaxValue)
                        hash = ~hash;
 
                    outputDictionary[hash].RepeatCount = hashCount;
                }
            }
        }
 
        private static unsafe void core4(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin)
        {
            var len = 4;
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
 
            var byteCount = len;
            var hashDictionary = new HashSet<int>();
            int invertThreshold = short.MaxValue;
            invertThreshold *= 256;
            invertThreshold--;
 
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var hash = *(int*)ptr;// FastHash(ptr, byteCount);
                if (hash <= invertThreshold)
                    hash = ~hash;
 
                AddOrIncHash(outputDictionary, hash, begin, ptr, len);
 
                //Следующий символ
                ptr++;
            }
        }
 
        private static unsafe void core567(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin, int len)
        {
            //ВАЖНО! Этот метод не обрабатывает для 5 байтовых фрагментов - 3 последних, для 6 байтовых - 2 последних, для 7 байтовых - 1 последний
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - 8 + 1;
            byte* ptr = begin;
 
            var byteCount = len;
            var hashDictionary = new HashSet<int>();
 
            long mask = 0;
            if (len == 7) mask = 0b00000000_11111111_11111111_11111111_11111111_11111111_11111111_11111111;
            else if (len == 6) mask = 0b00000000_00000000_11111111_11111111_11111111_11111111_11111111_11111111;
            else if (len == 5) mask = 0b00000000_00000000_00000000_11111111_11111111_11111111_11111111_11111111;
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var hashLong = *(long*)ptr;// FastHash(ptr, byteCount);
                hashLong &= mask;
 
                var hash = (unchecked((int)((long)hashLong)) ^ (int)(hashLong >> 32));
 
                AddOrIncHash(outputDictionary, hash, begin, ptr, len);
                
 
                //Следующий символ
                ptr++;
            }
 
        }
 
        private static unsafe void core8(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin)
        {
            var len = 8;
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
 
            var byteCount = len;
            var hashDictionary = new HashSet<int>();
            //Внутренний цикл использует арифметику указателей
            //чтобы быть быстрым
            while (ptr < end)
            {
                //Считаем хэш фрагмента памяти
                var hashLong = *(long*)ptr;// FastHash(ptr, byteCount);
                var hash = (unchecked((int)((long)hashLong)) ^ (int)(hashLong >> 32));
 
                AddOrIncHash(outputDictionary, hash, begin, ptr, len);
 
                //Следующий символ
                ptr++;
            }
        }
 
 
        private static unsafe void coreUniversal(byte[] text, Dictionary<int, hashInfo> outputDictionary, byte* textPtrBegin, int len)
        {
            byte* begin = textPtrBegin;
            byte* end = begin + text.Length - len + 1;
            byte* ptr = begin;
 
            var byteCount = len;
 
            fixed (long* power31ptr = power31Table)
            {
                //Внутренний цикл использует арифметику указателей
                //чтобы быть быстрым
                while (ptr < end)
                {
                    //Считаем хэш фрагмента памяти
                    var hash = FastHash(ptr, byteCount, power31ptr);
 
                    AddOrIncHash(outputDictionary, hash, begin, ptr, len);
 
                    //Следующий символ
                    ptr++;
                }
            }
        }
    }
}
11,3 сек на файле 62,6 Мб

Добавлено через 2 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
ну в некотором роде оптимизация - это инициатива форумчан, игра умов, я, всё что мы обсуждаем, считаю StringBuilder'ом без проблем. Если бы вы с Элд Хасп не помогли с последними рекомендациями - я бы остался на той самой границе. Дело в том что эта часть расчётов является только инструментом для получения данных, которые уходят дальше в другую программу и по сути она нужна только один раз (повторно в основном использую если нужно что-то проверять с другими данными).
Если скорость решения для вас приемлема, то тогда смысла нет в оптимизации.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
14.12.2020, 12:13  [ТС]
Цитата Сообщение от VBDUnit Посмотреть сообщение
Если скорость решения для вас приемлема, то тогда смысла нет в оптимизации.
Есть. Наступает соблазн считать файлы бОльшего объема, они дают меньшую погрешность. Просто с Элд Хасп и некоторыми другими форумчанами у нас конфликт на тему того - чем является форум и вообще - для чего все мы тут собрались.
Я не проф.программист и для меня программирование как молоток - а оптимизации, прилизывания - это как шахматы. И это абсолютно не связанные вещи.
Это всё лирика. Спасибо за код.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
14.12.2020, 18:27  [ТС]
Цитата Сообщение от VBDUnit Посмотреть сообщение
Собственно, последний вариант с минимизированным числом поисков
Это что за проект? У меня на 4.8/preview ошибки
Миниатюры
Ботлнек String/StringBuilder  
0
Эксперт .NET
 Аватар для Usaga
14784 / 9558 / 1366
Регистрация: 21.01.2016
Сообщений: 36,046
14.12.2020, 18:29
Цитата Сообщение от belalugoci Посмотреть сообщение
Это что за проект?
Похоже, что .NET Core 5.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
14.12.2020, 18:40  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Похоже, что .NET Core 5.
полез качать. всегда интересно зачем делать установщик VS который по 10 раз на день может надоедать с установками, но в нём самом имеется только core 3.1...
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
14.12.2020, 19:07
Цитата Сообщение от belalugoci Посмотреть сообщение
Я не проф.программист и для меня программирование как молоток - а оптимизации, прилизывания - это как шахматы. И это абсолютно не связанные вещи.
Это зависит от задачи.

Если вы считаете гидродинамику плотину, т не важно за сколько будет произведён расчёт: 1с, 1м, 1 час ли даже день.
Это дополнительное удобство, но не являющееся принципиальным.


Если же вы создаёте программу-архиватор, то она будет конкурировать с другими архиваторами.
И здесь скорость вычисление, объём использованной памяти являются прямыми, первостепенными критериями оценки приложения.
Программа может обеспечивать ультра сжатие, но скорость её работы не позволит пользователям её использовать.
Очень много есть теоретических алгоритмов сжатия, но недопустимо медленных.
Именно по причине оптимальности скорости и ресурсов на рынке в основном представлены блочные алгоритмы.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
14.12.2020, 19:34  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это зависит от задачи.
это зависит от критериев оценки эффективности, а они задаются заказчиком, а заказчик это я.
поэтому если я могу за 30 минут на string написать код который даст мне ответ на вопрос, то мне абсолютно плевать как именуются имена переменных, сколько там скобочек и можно ли было всё сделать через ulong.
Инструмент использован - результат получен. Остальное это возня никому не интересная.
А вот сидя вечером с коньячком и сигарой от нечего делать можно поставить себе задачу и попробовать её решить. Например сделать то же самое но через рекурсию, или без массивов или через ulong.
Мы не пишем код для ядерных ракет или код для работы ИВЛ, это просто действия в духе "поднял, перенес, поставил".
И, уж не знаю, удивлю я вас или нет, но мир разработки, не побоюсь переоценить - на 80% состоит из говнокода и говнокодеров. Сначала разработка - чтобы работало, потом продажа, а по факту продаж или доработка или похороны. Поэтому на этом форуме можно вечно притворяться и играть в идеальный мир разработки, но его просто нет - устройства глючат, программы виснут, спутники падают, люди умирают.
Поэтому я просто не вижу смысла поднимать такие темы. Программа пишется с целью посчитать 2+2, она считает и выдает 4. Всё. Остальное лирика. Не вижу смысла поднимать и обсуждать подобные темы я никогда не соглашусь с вашей точкой зрения. Ваши принципы в реальной жизни не работают, этого достаточно чтобы считать их как минимум недалёкими. Это донкихотство. Я работал на двух машиностроительных заводах, даже "чинил", если можно так сказать огромные станки Siemens, еще какой-то там швейцарской компании были лазерные CO2 резчики, работал в трех банках (то есть довелось взаимодействовать в том числе с Центробанком) и я ни в одной компании ни разу не встретил софт написанный НЕ криво.
Бри́тва Хэ́нлона (англ. Hanlon's razor) — презумпция, согласно которой при поисках причин неприятных событий должны прежде всего предполагаться человеческие ошибки, и лишь во вторую очередь — чьи-то сознательные злонамеренные действия
Ошибки человека - это константа.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
14.12.2020, 19:53
Цитата Сообщение от belalugoci Посмотреть сообщение
это зависит от критериев оценки эффективности, а они задаются заказчиком, а заказчик это я.
Ни сколько с этим не спорю,
Я об этом и пишу.
Всё очень индивидуально и зависит от различных взаимосвязанных условий кокретной задачи.

В этом же топике взаимное непонимание было вызвано самим его названием "Болтнек..".
То есть в названии топика вы обозначили приоритетность оптимизации по скорости и памяти.
Когда же вам стали писать о причинах этого вы заняли непонятную позицию "моя задача. что хочу то и ворочу. сами дураки".
Естественно, это вызвало неприятие.


Поэтому, в данном случае, все споры были только касательно обозначенного названия топика и вашей неадекватной реакции на ответы по проблеме обозначенной этим названием.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
14.12.2020, 20:46  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В этом же топике взаимное непонимание было вызвано самим его названием "Болтнек..".
Ну начнем с того, что проблемы со string/StringBuilder обозначены не мной, я лишь выделил обсуждение в другую тему. Ну а название отражает суть - обсуждение узких мест их применения. Ну так обсуждайте или не обсуждайте, но их, а не меня. Если вы считаете что тема недостойна обсуждения и все ответы давно существуют - вы например можете на это указать, дать ссылку на материал. Очевидное для вас может быть неочевидным для других.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
То есть в названии топика вы обозначили приоритетность оптимизации по скорости и памяти.
Нет.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Когда же вам стали писать о причинах этого вы заняли непонятную позицию "моя задача. что хочу то и ворочу. сами дураки".
Перечитал 3 страницы и не увидел там с моей стороны такой позиции.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Естественно, это вызвало неприятие.
Совсем неестественно.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Поэтому, в данном случае, все споры были только касательно обозначенного названия топика и вашей неадекватной реакции на ответы по проблеме обозначенной этим названием.
Во-первых про тему никто ни разу ничего не спросил. Во-вторых мы медленно двигались по коду и его меняли, вот к 7-ой странице даже получилось весьма неплохо. Причем тема со StringBuilder долго была актуальной, так как лучшей реализации не было. Собственно я ей до сих пор пользуюсь так как знаю как с ней работать и как получать те данные которые мне нужны.

Как только вы в принципе перестанете заниматься выпрямлением моих рук - проблема исчезнет сама по себе.
Для человека знающего 1% C# я вполне сносно пишу, но вы считаете что я просто обязан писать как Бог. Этого не будет по объективным причинам, смиритесь. Вон сегодня целую тему мило с Usaga обсудили, код переписали, работало до, работает и после. Всё тихо и спокойно, потому что никто не касался меня и моих рук. В конце правда это случилось, но я стойко это перенёс XD.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
14.12.2020, 20:59
Цитата Сообщение от belalugoci Посмотреть сообщение
Перечитал 3 страницы и не увидел там с моей стороны такой позиции.
Ну, о вашем "В чужом глазу соринку видеть, а в своем бревна не замечать" мы уже не раз говорили.
Давайте оставим эту тему, а то опять превратится в пустой флуд.
Просто примите, что то как вы видите себя, своё поведение (в общении), совершенно не соответствует тому как их видят другие (в этом форуме).
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
15.12.2020, 04:39  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
в этом форуме
это самое важное замечание, потому что я именно об этом уже и говорил.
если меня понимают и принимают последние 35 лет на разных ресурсах в интернете и никаких проблем и конфликтов не возникает, то проблема действительно не во мне. Л - логика.
0
Эксперт .NET
 Аватар для Usaga
14784 / 9558 / 1366
Регистрация: 21.01.2016
Сообщений: 36,046
15.12.2020, 05:35
Цитата Сообщение от belalugoci Посмотреть сообщение
потому что никто не касался меня и моих рук. В конце правда это случилось
Да вроде бы не было ничего такого. Строго по теме шли.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.12.2020, 05:35

Невозможно очистить StringBuilder после исключения OutOfMemoryException
Привет всем. Делаю небольшой текстовый редактор и натолкнулся на следующую проблему: при загрузке достаточно большого файла через...

StringBuilder: Строка не корректно создается, перемешиваются все поля
приложение клиент-сервер. клиент создает запрос на сервер, сервер с помощью StringBuilder из словаря формирует строку для передачи по...

В чем разница между StringWriter и StringBuilder и когда нужно использовать эти классы?
Подскажите, пожалуйста, в чем разница между StringWriter и StringBuilder и когда нужно использовать эти классы? То, что есть в этих...

Несколько вопросов по примеру из книги по C# про строки (string и String.Format)
Я нашел такой пример кода: private void butFormatStr_Click(object sender, EventArgs e { string AutoName; AutoName =...

Реализация интерфейса IEqualityComparer для HashSet<Dictionary<string, string>>
Код выдает &quot;2&quot;, что, логично, а хотелось бы, чтобы выдавал &quot;1&quot;, так как содержание словарей одинаковое. Подскажите, пожалуйста,...


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

Или воспользуйтесь поиском по форуму:
220
Ответ Создать тему
Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru