Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/14: Рейтинг темы: голосов - 14, средняя оценка - 4.64
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169

Не как не могу понять код с Task, lock

20.12.2020, 20:58. Показов 2862. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго всем времени!
У меня появились затруднение с пониманием кода, а это в в общем то с lock`ом и Task`ом.

Я хотел написать программу которая очень и очень много раз записывает в текстовой файл пароли.
И я хотел бы делать это с двумя потоками.

Решил взять пример кода, тот что я не как не могу понять.

Вот он:

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
using System;
using System.IO;
using System.Threading.Tasks;
using System.Timers;
 
internal class Program
{
    private static readonly object _syncObject = new object();
 
    private static void Main(string[] args)
    {
        TextWriter textWriter = new StreamWriter("доконца.txt");
 
 
        var timer = new Timer { Interval = 1 };
        timer.Elapsed +=
            (sender, eventArgs) =>
            {
                for (var i = 0; i < 10; i++)
                    Task.Run(() => Log("МЫ БУДЕМ ПИТЬ", textWriter));
            };
        timer.Start();
 
        Console.ReadKey(true);
        timer.Stop();
        textWriter.Close();
    }
 
    public static void Log(string logMessage, TextWriter w)
    {
        lock (_syncObject)
        {
            w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                DateTime.Now.ToLongDateString());
            w.WriteLine("  :");
            w.WriteLine("  :{0}", logMessage);
            w.WriteLine("-------------------------------");
 
            w.Flush();
        }
    }
}
Вроде бы все легко, есть метод Log который принимает параметры "Слово", и сам "TextWrite".
И выполняется запись в файл время, и слово. И все это в блоке lock.

И весь вот этот метод выполняется в 10 потоков каждое время (Я не до конца понял что значит "Interval = 1", а именно что значит 1, наверное это миллисекунда.).

Так вот, вопрос состоится в том, почему потоки работают? Ведь внутри блоке lock, код блокируется и становиться не доступным. Но почему то когда я ставлю 10-50 потоков то запись в файл становиться быстрее.

Прошу объяснить мне пожалуйста, потому что в моей программе код реально блокируется.
И сначала выполняется 1 цикл, потом второй, и так далее.
А мне нужно что бы они выполнялись синхронно хоть и не идеально.

Добавлено через 9 минут
Вот код моей программы. Она уже на Windows forms.

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
private void btnPassGen_Click(object sender, EventArgs e)
        {
            timerUpdateResult.Enabled = true;
            textWrite = new StreamWriter("Password.txt");
            //path = textBoxPath.Text;
            _sourceToken = new CancellationTokenSource();
            CancellationToken token = _sourceToken.Token;
            
                for (int i = 1; i <= Convert.ToInt32(textBoxNumberTask.Text); i++)
                {
                    Task.Run(() => GenGenerator(token, textWrite), token);
                }
        }
 
public void GenGenerator(CancellationToken token, TextWriter w)
        {
            lock (_syncObject)
            {
                int dNumPass = 0;
                timerUpdateResult.Enabled = true;
                listGenPass.Clear();
                char[] word = "abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ1234567890!№;%:?*()'".ToCharArray();
                var gen = new Generator(Convert.ToInt32(textBoxNumberPass.Text), word);
 
                foreach (var item in gen)
                {
                    dNumPass++;
                    token.ThrowIfCancellationRequested();
                    //listGenPass.Add(item.ToString());
                    w.WriteLine(item + " : " + dNumPass);
                    w.Flush();
 
                }
                timerUpdateResult.Enabled = false;
                textWrite.Close();
                //w.WriteLine("Окончание программы: {0}", Secound.ToString());
            }
        }
Тут все наверное не все тоже самое.
Но! Создаю так же файл, под названием Password.
Запускаю TASK`и, а именно 5 штук. Они запускают метод "GenGenerator", передаю параметры токен и TextWriter w.
Ну в этом методе все понятно, только есть такая штука как foreach(var item in gen).

В класс gen я передаю сгенерированный пароль.

Добавлено через 3 минуты
Забыл написать какой результат в моей программе.
Вот такой:

aaa : 1
baa : 2
caa : 3
aaa : 1
baa : 2
caa : 3
aaa : 1
baa : 2
caa : 3


А я не как не могу понять почему у меня не такой вот результат:

aaa : 1
aaa : 1
aaa : 1
baa : 2
baa : 2
baa : 2
caa : 3
caa : 3
caa : 3
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.12.2020, 20:58
Ответы с готовыми решениями:

Не могу понять принцип действия Task.Run
Добрый день, форумчане, не могу понять как работает запуск асинхронных процессов. Поясню в чём вопрос. При первом вводе команды метод не...

Не могу понять как написать код
Определить, какое число в массиве встречается чаще всего, вывести его. Вывести позиции расположения, и количество повторов.

Не могу понять как работает этот код
пожалуйста удалите тему

14
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
20.12.2020, 21:39
Ня!
Что значит, должны выполняться синхронно?
Зачем 2 потока для записи в 1 файл? Быстрее? Почему, ведь файл 1, диск 1?

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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
 
namespace ThreadLog
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var token = new CancellationTokenSource();
            var consoleLogger = new ConsoleLogger();
            var synclogger = new LogSyncProxy(consoleLogger);
 
            var tasks = new List<Task>();
            for (var i = 0; i < 10; i++)
            {
                var data = new TaskData(synclogger, token.Token);
                tasks.Add(Task.Factory.StartNew(
                    o => Generate((TaskData) o),
                    data,
                    token.Token));
            }
 
            Console.ReadLine();
 
            token.Cancel();
            Task.WaitAll(tasks.ToArray());
            synclogger.Shutdown();
        }
 
        private static void Generate(TaskData taskData)
        {
            while (!taskData.Token.IsCancellationRequested)
                taskData.Logger.Write(new Message(DateTime.Now.ToString("HH:mm:ss.ffff")));
        }
    }
 
    public class TaskData
    {
        public TaskData(ILogger logger, CancellationToken token)
        {
            Logger = logger;
            Token = token;
        }
 
        public ILogger Logger { get; }
        public CancellationToken Token { get; }
    }
 
    public class Message
    {
        public Message(string value)
        {
            Value = value;
        }
 
        public string Value { get; set; }
    }
 
    public interface ILogger
    {
        void Write(Message message);
    }
 
    public class ConsoleLogger : ILogger
    {
        public void Write(Message message)
        {
            Console.WriteLine(message.Value);
        }
    }
 
    public class LogSyncProxy : ILogger
    {
        private readonly ILogger _logger;
        private readonly ConcurrentQueue<Message> _queue = new ConcurrentQueue<Message>();
        private readonly Task _task;
        private readonly CancellationTokenSource _token = new CancellationTokenSource();
 
        public LogSyncProxy(ILogger logger)
        {
            _logger = logger;
            _task = Task.Factory.StartNew(
                o => Grinder((CancellationToken) o),
                _token.Token,
                TaskCreationOptions.LongRunning);
        }
 
        public void Write(Message message)
        {
            _queue.Enqueue(message);
        }
 
        private void Grinder(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
                if (_queue.TryDequeue(out var message))
                    _logger.Write(message);
                else
                    token.WaitHandle.WaitOne(100);
        }
 
        public void Shutdown()
        {
            _token.Cancel();
            _task.Wait();
        }
    }
}
1
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
21.12.2020, 15:34  [ТС]
Rius, здравствуйте!
Спасибо большое конечно за ваше старание. За такой громадный код.
Но я что то не понимаю какое действие выполняет программу, на консоль записывает как я понял прокси, но почему то то одинаковые то они изменяются, не много не понял. Можете пожалуйста не расписывать каждую строчку, а просто объяснить что он выполняет и к чему этот пример.

Цитата Сообщение от Rius Посмотреть сообщение
Что значит, должны выполняться синхронно?
Я имею в виду что бы каждый поток выполнял свое действие и записывал в результат в файл.

Цитата Сообщение от Rius Посмотреть сообщение
Зачем 2 потока для записи в 1 файл? Быстрее? Почему, ведь файл 1, диск 1
Получается смысла нет записывать в 1 файл с разных потоков результаты? Так как я не в первый раз слышу.
Но сами результаты у меня записываются быстро, я думал можно было и быстрее
Либо наверное уже не имеет не какого смысла?
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
21.12.2020, 16:24
Два потока пишут в один метод одного объекта.
Тот принимает от разных писателей в очередь и отдельным одним потоком считывает из неё по одному элементу и пишет в один файл.

Добавлено через 3 минуты
Цитата Сообщение от QmlwZ Посмотреть сообщение
Я имею в виду что бы каждый поток выполнял свое действие и записывал в результат в файл.
Здесь каждый поток выполняет своё действие и передаёт результат дальше для записи.
Цитата Сообщение от QmlwZ Посмотреть сообщение
Получается смысла нет записывать в 1 файл с разных потоков результаты? Так как я не в первый раз слышу.
Надо проверять. Если поставщик данных для записи может обеспечить их достаточную скорость поставки, чтобы нагрузить запись на диск, то смысла в нескольких потоках нет. Здесь это не особо важно, так как есть синхронизатор.
0
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
21.12.2020, 16:48  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Два потока пишут в один метод одного объекта.
Тот принимает от разных писателей в очередь и отдельным одним потоком считывает из неё по одному элементу и пишет в один файл.
Ай! Точно, а то я пишу вам про какие то прокси, не заметил что это время.
Хорошо, спасибо вам, все таки хоть и понял смысл, ну наверное все таки не буду записывать в файл результаты в нескольких потоках.
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
21.12.2020, 17:03
Лучший ответ Сообщение было отмечено QmlwZ как решение

Решение

А здесь поток записи - один.
Это потоков создания данных 10 штук.
Так что используйте.

Добавлено через 4 минуты
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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace ThreadLog
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var token = new CancellationTokenSource();
            using var fileLogger = new FileLogger("file.log");
            using var synclogger = new LogSyncProxy(fileLogger);
 
            var tasks = new List<Task>();
            for (var i = 0; i < 10; i++)
            {
                var data = new TaskData(synclogger, token.Token);
                tasks.Add(Task.Factory.StartNew(
                    o => Generate((TaskData) o),
                    data,
                    token.Token));
            }
 
            Console.ReadLine();
 
            token.Cancel();
            Task.WaitAll(tasks.ToArray());
        }
 
        private static void Generate(TaskData taskData)
        {
            while (!taskData.Token.IsCancellationRequested)
                taskData.Logger.Write(new Message(DateTime.Now.ToString("HH:mm:ss.ffff")));
        }
    }
 
    public class TaskData
    {
        public TaskData(ILogger logger, CancellationToken token)
        {
            Logger = logger;
            Token = token;
        }
 
        public ILogger Logger { get; }
        public CancellationToken Token { get; }
    }
 
    public class Message
    {
        public Message(string value)
        {
            Value = value;
        }
 
        public string Value { get; set; }
    }
 
    public interface ILogger
    {
        void Write(Message message);
    }
 
    public class ConsoleLogger : ILogger
    {
        public void Write(Message message)
        {
            Console.WriteLine(message.Value);
        }
    }
 
    public class FileLogger : ILogger, IDisposable
    {
        private readonly StreamWriter _writer;
 
        public FileLogger(string filename)
        {
            _writer = new StreamWriter(filename, true, Encoding.UTF8);
        }
 
        public void Dispose()
        {
            _writer?.Flush();
            _writer?.Close();
            _writer?.Dispose();
        }
 
        public void Write(Message message)
        {
            Console.WriteLine(message.Value);
        }
    }
 
    public class LogSyncProxy : ILogger, IDisposable
    {
        private readonly ILogger _logger;
        private readonly ConcurrentQueue<Message> _queue = new ConcurrentQueue<Message>();
        private readonly Task _task;
        private readonly CancellationTokenSource _token = new CancellationTokenSource();
 
        public LogSyncProxy(ILogger logger)
        {
            _logger = logger;
            _task = Task.Factory.StartNew(
                o => Grinder((CancellationToken) o),
                _token.Token,
                TaskCreationOptions.LongRunning);
        }
 
        public void Dispose()
        {
            _token.Cancel();
            _task.Wait();
        }
 
        public void Write(Message message)
        {
            _queue.Enqueue(message);
        }
 
        private void Grinder(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
                if (_queue.TryDequeue(out var message))
                    _logger.Write(message);
                else
                    token.WaitHandle.WaitOne(100);
        }
    }
}
1
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
21.12.2020, 18:40  [ТС]
Rius, спасибо вам большое еще раз.

Добавлено через 4 минуты
Конечно я не очень то и понял уш так сильно код. Все равно есть вопросы, еще есть о том что файл то создается txt, а вот туда не чего не записывается. Да и вот самый главный вопрос, при изменение количество потоков скорость одинаковая.
Наверное я просто не вник в код.
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
21.12.2020, 18:54
Упс, в FileLogger:
C#
1
2
3
4
        public void Write(Message message)
        {
            _writer.WriteLine(message.Value);
        }
Добавлено через 52 секунды
Вы скорость можете вычислить? Хотя бы примерно по изменению размера файл в проводнике?

Добавлено через 6 минут
У меня вышло 93МБ в секунду.
Во 2-й раз 164 МБ/с.
В общем, много.
1
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
21.12.2020, 19:24  [ТС]
Rius, спасибо сейчас записывается в файл, но вот вопрос, а как вы так проверили скорость загрузки?
Если у меня в папки следить как заполняется файл то он только пролагивается и моментально заполняеться.
Наверное вы не о том подумали.
Я вот про это :
Миниатюры
Не как не могу понять код с Task, lock  
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
21.12.2020, 19:32
Этот пример пишет время в файл. Объём файла по завершении известен. Делим объём на затраченное время.

Если у вас файл заполняется моментально, то проблемы нет?
0
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
21.12.2020, 20:08  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Этот пример пишет время в файл. Объём файла по завершении известен. Делим объём на затраченное время.
Спасибо за такую информацию.

Провел тесты, но на скорую руку.

Сразу отмечу, в коде тот что я давал выше, там есть как раз тот код который вы мне подсказывали не давно.
Вот она: Перегрузка памяти, приложение лагает при заполнение HeshSet

В общем то, ваши тесты показали вот так (все будет в кб):
1. 10.22 сек = 157 132 кб при одном потоке.
2. 10.31 сек = 133 078 кб при 10 потоков.


Не знаю почему так, но я записывал пароли, которые перебираются, и вы помогли мне с кодом.
С 10 потоков я уже вижу дубликаты, и я знаю как избавиться. Но вот почему то с 10 потоков нет не какого результата и то меньше выдало кб с 10 секунд, ну наверное это уже может зависит от моего компьютера.

Теперь с моей программой ту что я писал в самом начале, там то же ваш способ перебор паролей который вы мне подсказали, за это конечно спасибо большое вам.

1. 10.11 сек = 23 210 кб при 5 потоков.
2. 10.32 сек = 34 912 кб при 1 потоке.


И это еще не все, такой результат выдавал тогда когда я использовал в коде вот это :

C#
1
2
3
4
5
6
foreach (var item in gen)
                {
                    token.ThrowIfCancellationRequested();
                    w.WriteLine(item);
                    w.Flush(); //С использованием Flush.
                }
Если без него то вот такие результаты :

1. 10.62 сек = 221 150 кб при 5 потоков.
2. 10.16 сек = 260 113 кб при 1 потоке.


Не знаю почему так. Даже растерян.
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
21.12.2020, 20:54
С тем генератором не смысла в потоках. Для потоков надо указать диапазоны, которые каждый экземпляр будет генерировать.



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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace ThreadLog
{
    public class Program
    {
        private static readonly char[] Alphabet = Enumerable.Range(0, 26).Select(x => (char) ('a' + x)).ToArray();
 
        private static void Main(string[] args)
        {
            var numberOfCharacters = Alphabet.Length;
            var lengthOfWord = 10;
            var filename = "R:\\file.log";
 
            
            
            BigInteger numberOfVariants = 1;
            for (var i = 0; i < lengthOfWord; i++) numberOfVariants *= numberOfCharacters;
            Console.WriteLine($"Characters: {numberOfCharacters}, length of word: {lengthOfWord}");
            Console.WriteLine($"Number of variants: {numberOfVariants}");
            Console.WriteLine("Expected size of file: {0} MB", numberOfVariants * (lengthOfWord + 2) / (1024 * 1024));
 
 
            var sw = new Stopwatch();
            var token = new CancellationTokenSource();
            using var fileLogger = new FileLogger(filename);
            using var synclogger = new LogSyncProxy(fileLogger);
 
            var tasks = new List<Task>();
 
            sw.Start();
 
            for (var i = 0; i < 1; i++)
            {
                //var data = new TaskData(synclogger, token.Token);
                var data = new TaskData(fileLogger, token.Token, lengthOfWord);
                tasks.Add(Task.Factory.StartNew(
                    o => Generate((TaskData) o),
                    data,
                    token.Token));
            }
 
            Console.ReadLine();
 
            token.Cancel();
            Task.WaitAll(tasks.ToArray());
 
            sw.Stop();
            var fileSize = ToMegabytes(new FileInfo(filename).Length);
 
            Console.WriteLine(
                $"Time: {sw.Elapsed}, Size: {fileSize} MB, Speed: {fileSize / sw.Elapsed.TotalSeconds: 0} MB/second");
        }
 
        private static long ToMegabytes(long value)
        {
            return value / (1024 * 1024);
        }
 
        private static void Generate(TaskData taskData)
        {
            var gen = new Generator(taskData.LengthOfWord, Alphabet);
            var enumerator = gen.GetEnumerator();
            var logger = taskData.Logger;
            var token = taskData.Token;
 
            foreach (var item in gen)
            {
                if (token.IsCancellationRequested)
                    break;
                logger.Write(new Message(item));
            }
        }
    }
 
    public class TaskData
    {
        public TaskData(ILogger logger, CancellationToken token, int lengthOfWord)
        {
            Logger = logger;
            Token = token;
            LengthOfWord = lengthOfWord;
        }
 
        public ILogger Logger { get; }
        public CancellationToken Token { get; }
        public int LengthOfWord { get; }
    }
 
    public class Message
    {
        public Message(string value)
        {
            Value = value;
        }
 
        public string Value { get; set; }
    }
 
    public interface ILogger
    {
        void Write(Message message);
    }
 
    public class ConsoleLogger : ILogger
    {
        public void Write(Message message)
        {
            Console.WriteLine(message.Value);
        }
    }
 
    public class FileLogger : ILogger, IDisposable
    {
        private readonly StreamWriter _writer;
 
        public FileLogger(string filename)
        {
            _writer = new StreamWriter(filename, false, Encoding.UTF8, 4 * 1024 * 1024);
        }
 
        public void Dispose()
        {
            _writer?.Flush();
            _writer?.Close();
            _writer?.Dispose();
        }
 
        public void Write(Message message)
        {
            _writer.WriteLine(message.Value);
            //_writer.Flush();
        }
    }
 
    public class LogSyncProxy : ILogger, IDisposable
    {
        private readonly ILogger _logger;
        private readonly ConcurrentQueue<Message> _queue = new ConcurrentQueue<Message>();
        private readonly Task _task;
        private readonly CancellationTokenSource _token = new CancellationTokenSource();
 
        public LogSyncProxy(ILogger logger)
        {
            _logger = logger;
            _task = Task.Factory.StartNew(
                o => Grinder((CancellationToken) o),
                _token.Token,
                TaskCreationOptions.LongRunning);
        }
 
        public void Dispose()
        {
            _token.Cancel();
            _task.Wait();
        }
 
        public void Write(Message message)
        {
            _queue.Enqueue(message);
        }
 
        private void Grinder(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
                if (_queue.TryDequeue(out var message))
                    _logger.Write(message);
                else
                    token.WaitHandle.WaitOne(100);
        }
    }
 
    public class Generator
    {
        private readonly char[] _characters;
        private readonly int _length;
 
        public Generator(int length, params char[] characters)
        {
            _length = length;
            _characters = characters;
        }
 
        public IEnumerator<string> GetEnumerator()
        {
            var buffer = new char[_length];
            var indexes = new int[_length];
            var max = _characters.Length;
            var isCompleted = false;
 
            while (!isCompleted)
            {
                for (var i = 0; i < _length; i++)
                    buffer[i] = _characters[indexes[i]];
 
                yield return new string(buffer);
 
                for (var j = 0; j < _length + 1; j++)
                {
                    if (j >= _length)
                    {
                        isCompleted = true;
                        break;
                    }
 
                    if (++indexes[j] < max)
                        break;
                    indexes[j] = 0;
                }
            }
        }
    }
}
Какой длины вы пароли создаёте и из скольки символов?
1
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
22.12.2020, 15:15  [ТС]
Rius, Хох!! Вы серьезно профессионал своего дело! Не знаю, мои вопросы, мои проблемы думаю для вас реально как муха, просто взяли и написали...

Мои результаты намного скромнее, ну я думаю это уже зависит от компьютера, а у меня он не самый такой лучший.

И еще вот, я щас и буду ковыряться и вникать очень хорошо в код, но пока что не могу особенно понять ошибку если менять количество потоков.

C#
1
2
3
4
5
6
7
8
9
for (var i = 0; i < 1; i++) // Если сделаю 2, то ошибка.
            {
                //var data = new TaskData(synclogger, token.Token);
                var data = new TaskData(fileLogger, token.Token, lengthOfWord);
                tasks.Add(Task.Factory.StartNew(
                    o => Generate((TaskData)o),
                    data,
                    token.Token));
            }
Если я поменяю в цикли 1 например на 2, то через некоторые время появится ошибка:

System.ArgumentOutOfRangeException: "Index and count must refer to a location within the buffer."

Именно в этой функции:
C#
1
2
3
4
5
public void Write(Message message)
        {
            _writer.WriteLine(message.Value);
            //_writer.Flush();
        }
/

А если я просто нажму "Продолжить", то все нормально, но если я нажму на Enter, то в место результатах выведется вот это:
Кликните здесь для просмотра всего текста

Unhandled exception. System.AggregateException: One or more errors occurred. (Specified argument was out of the range of valid values.)
---> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
at System.IO.FileStream.WriteSpan(ReadOnlyS pan`1 source)
at System.IO.FileStream.Write(Byte[] array, Int32 offset, Int32 count)
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.WriteLine(String value)
at DunteThread.FileLogger.Write(Message message) in E:\Users\Professional\Desktop\DunteThrea d\DunteThread\Program.cs:line 138
at DunteThread.Program.Generate(TaskData taskData) in E:\Users\Professional\Desktop\DunteThrea d\DunteThread\Program.cs:line 78
at DunteThread.Program.<>c.<Main>b__1_0(Obj ect o) in E:\Users\Professional\Desktop\DunteThrea d\DunteThread\Program.cs:line 45
at System.Threading.Tasks.Task.InnerInvoke( )
at System.Threading.Tasks.Task.<>c.<.cctor> b__274_0(Object obj)
at System.Threading.ExecutionContext.RunFro mThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.ExecutionContext.RunFro mThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithT hreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.WaitAllCore( Task[] tasks, Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.WaitAll(Task[] tasks)
at DunteThread.Program.Main(String[] args) in E:\Users\Professional\Desktop\DunteThrea d\DunteThread\Program.cs:line 53

E:\Users\Professional\Desktop\DunteThrea d\DunteThread\bin\Debug\netcoreapp3.1\Du nteThread.exe (процесс 9432) завершил работу с кодом 0.
Чтобы автоматически закрывать консоль при остановке отладки, включите параметр "Сервис" ->"Параметры" ->"Отладка" -> "Автоматически закрыть консоль при остановке отладки".
Нажмите любую клавишу, чтобы закрыть это окно…


Длины пароля 5, количество символов 72.
Миниатюры
Не как не могу понять код с Task, lock  
0
Эксперт .NET
 Аватар для Rius
13156 / 7714 / 1679
Регистрация: 25.05.2015
Сообщений: 23,507
Записей в блоге: 14
22.12.2020, 18:29
Лучший ответ Сообщение было отмечено QmlwZ как решение

Решение

Цитата Сообщение от QmlwZ Посмотреть сообщение
Если я поменяю в цикли 1 например на 2, то через некоторые время появится ошибка:
System.ArgumentOutOfRangeException: "Index and count must refer to a location within the buffer."
Да, потому что синхронизатор был убран из цепочки. К некоторым объектам нельзя обращаться из разных потоков.

Для многопоточности надо переделывать генератор, чтобы в каждом потоке он работал в отдельном диапазоне. Нет смысла одни и те же строки дважды писать.


Вот так чуть быстрее будет
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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace ThreadLog
{
    public class Program
    {
        private static readonly char[] Alphabet = Enumerable.Range(0, 72).Select(x => (char) (' ' + x)).ToArray();
 
        private static void Main(string[] args)
        {
            var numberOfCharacters = Alphabet.Length;
            var lengthOfWord = 5;
            var filename = "D:\\file.log";
 
 
            BigInteger numberOfVariants = 1;
            for (var i = 0; i < lengthOfWord; i++) numberOfVariants *= numberOfCharacters;
            Console.WriteLine($"Characters: {numberOfCharacters}, length of word: {lengthOfWord}");
            Console.WriteLine($"Number of variants: {numberOfVariants}");
            Console.WriteLine("Expected size of file: {0} MB", numberOfVariants * (lengthOfWord + 2) / (1024 * 1024));
 
 
            var sw = new Stopwatch();
            var token = new CancellationTokenSource();
            using var fileLogger = new FileLogger(filename);
            using var synclogger = new LogSyncProxy(fileLogger);
 
            var tasks = new List<Task>();
 
            Console.WriteLine("Press Ctrl+C to break");
            Console.CancelKeyPress += (sender, eventArgs) =>
            {
                eventArgs.Cancel = true;
                token.Cancel();
            };
 
            sw.Start();
 
            for (var i = 0; i < 1; i++)
            {
                //var data = new TaskData(synclogger, token.Token, lengthOfWord);
                var data = new TaskData(fileLogger, token.Token, lengthOfWord);
                tasks.Add(Task.Factory.StartNew(
                    o => Generate((TaskData) o),
                    data,
                    token.Token,
                    TaskCreationOptions.LongRunning,
                    TaskScheduler.Default));
            }
 
            try
            {
                while (!Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(5))) PrintSize(sw, filename);
            }
            catch (AggregateException ae)
            {
                Console.WriteLine("Exception was caught!");
                foreach (var innerException in ae.InnerExceptions) Console.WriteLine(innerException.Message);
            }
 
            sw.Stop();
 
            PrintSize(sw, filename);
        }
 
        private static void PrintSize(Stopwatch sw, string filename)
        {
            var fileSize = ToMegabytes(new FileInfo(filename).Length);
 
            Console.WriteLine(
                $"Time: {sw.Elapsed}, Size: {fileSize} MB, Speed: {fileSize / sw.Elapsed.TotalSeconds: 0} MB/second");
        }
 
        private static long ToMegabytes(long value)
        {
            return value / (1024 * 1024);
        }
 
        private static void Generate(TaskData taskData)
        {
            var gen = new Generator(taskData.LengthOfWord, Alphabet);
            var enumerator = gen.GetEnumerator();
            var logger = taskData.Logger;
            var token = taskData.Token;
 
            foreach (var item in gen)
            {
                if (token.IsCancellationRequested)
                    break;
                logger.Write(item);
            }
        }
    }
 
    public class TaskData
    {
        public TaskData(ILogger logger, CancellationToken token, int lengthOfWord)
        {
            Logger = logger;
            Token = token;
            LengthOfWord = lengthOfWord;
        }
 
        public ILogger Logger { get; }
        public CancellationToken Token { get; }
        public int LengthOfWord { get; }
    }
 
    public interface ILogger
    {
        void Write(string message);
    }
 
    public class ConsoleLogger : ILogger
    {
        public void Write(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    public class FileLogger : ILogger, IDisposable
    {
        private readonly StreamWriter _writer;
 
        public FileLogger(string filename)
        {
            _writer = new StreamWriter(filename, false, Encoding.UTF8, 4 * 1024 * 1024);
        }
 
        public void Dispose()
        {
            _writer?.Flush();
            _writer?.Close();
            _writer?.Dispose();
        }
 
        public void Write(string message)
        {
            _writer.WriteLine(message);
            //_writer.Flush();
        }
    }
 
    public class LogSyncProxy : ILogger, IDisposable
    {
        private readonly ILogger _logger;
        private readonly ConcurrentQueue<string> _queue = new ConcurrentQueue<string>();
        private readonly Task _task;
        private readonly CancellationTokenSource _token = new CancellationTokenSource();
 
        public LogSyncProxy(ILogger logger)
        {
            _logger = logger;
            _task = Task.Factory.StartNew(
                o => Grinder((CancellationToken) o),
                _token.Token,
                TaskCreationOptions.LongRunning);
        }
 
        public void Dispose()
        {
            _token.Cancel();
            _task.Wait();
        }
 
        public void Write(string message)
        {
            _queue.Enqueue(message);
        }
 
        private void Grinder(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
                if (_queue.TryDequeue(out var message))
                    _logger.Write(message);
                else
                    token.WaitHandle.WaitOne(100);
        }
    }
 
    public class Generator
    {
        private readonly char[] _characters;
        private readonly int _length;
 
        public Generator(int length, params char[] characters)
        {
            _length = length;
            _characters = characters;
        }
 
        public IEnumerator<string> GetEnumerator()
        {
            var buffer = new char[_length];
            var indexes = new int[_length];
            var max = _characters.Length;
            var isCompleted = false;
 
            while (!isCompleted)
            {
                for (var i = 0; i < _length; i++)
                    buffer[i] = _characters[indexes[i]];
 
                yield return new string(buffer);
 
                for (var j = 0; j < _length + 1; j++)
                {
                    if (j >= _length)
                    {
                        isCompleted = true;
                        break;
                    }
 
                    if (++indexes[j] < max)
                        break;
                    indexes[j] = 0;
                }
            }
        }
    }
}
1
2 / 2 / 0
Регистрация: 10.08.2020
Сообщений: 169
22.12.2020, 21:23  [ТС]
Rius, хорошо, спасибо!!!!

Буду пользоваться вашим методом, после изучение кода.
Вы мне сильно помогли! Вот ваш опыт просто на глаза, другими словами вы крутой!

Добавлено через 1 минуту
Цитата Сообщение от Rius Посмотреть сообщение
Для многопоточности надо переделывать генератор, чтобы в каждом потоке он работал в отдельном диапазоне. Нет смысла одни и те же строки дважды писать.
Да, вот тут я понял. Спасибо еще раз!
Не раз вы меня выручаете.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.12.2020, 21:23
Помогаю со студенческими работами здесь

Не могу понять как организовать асинхронный код
Набросал с помощью гугла программу которая парсит конкретную веб страничку выкусывая линки и их заголовке. (Речь идёт о сайте stihi.ru и...

Сайт на Ucoze, не могу понять как добавить код
Всем привет, в веб программирование я полный ноль) Прошу помочь http://1a-med.ru/publ/vrachi/vrachi/khalilova_oksana_romanovna/18-1-0-38 ...

Не могу понять как работает этот код в деталях
dg1-&gt;Rows-&gt;Clear();//Очищяет в датагриде строки ifstream infile (StrToChar(openFileDialog1-&gt;FileName));//Чтение из файла ...

Не могу понять, как перевести код в WPF формат
Есть код для консоли правильный. Не могу понять, как сделать так, чтобы стороны a, b вводились из TextBox1 и TextBox2. Задача кода...

Не могу понять как исправить (код на FASM-е), простенькая программа
Написал программу для примера сдвигов, сдвигает нормально, вот только выводит каскадом (с начала выводит все переменные sent а потом только...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru