Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
 Аватар для extrimportal
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83

Про потоки с нуля

03.09.2017, 20:11. Показов 1964. Ответов 37
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пробую осилить потоки по записи в блоге от krapotkin
Читал много, но эта запись далась легче всего. Но все равно есть нюансы, ответы на которые сложно найти на просторах интернета.
Есть программа:
Delphi
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
unit UMainForm;
 
interface
 
uses
  classes, types, forms, Controls, StdCtrls, Dialogs, SysUtils;
 
type
  TMainForm = class(TForm)
    bStart: TButton;
    m1: TMemo;
    Edit1: TEdit;
    CheckBox1: TCheckBox;
    procedure bStartClick(Sender: TObject);
  private
    procedure Log(const s: string);
    procedure ThreadTerm(Sender: TObject);
  public
    Started:integer;
    Finished:integer;
    procedure RunThread();
 
  end;
 
var
  MainForm: TMainForm;
 
implementation
 
uses
  UMyThread;
 
 
const
  MAX_THREADS=5;
  SAME_TIME=50;
 
{$R *.dfm}
 
 
 
 
{ TMainForm }
 
 
procedure TMainForm.Log(const s:string);
begin
  m1.Lines.Add(s);
end;
 
procedure TMainForm.ThreadTerm(Sender: TObject);
var
  th:TMyThread absolute Sender; // очень древняя магия. обозначает th:=TMyThread(Sender)
begin
  log(th.URL + ':'+th.answer);
  inc(Finished);
  if Started<10 then
    RunThread;
  if Finished=MAX_THREADS then
  begin
    log('===========================');
    log('Работа окончена');
    bStart.Enabled := true;
  end;
end;
 
procedure TMainForm.bStartClick(Sender: TObject);
var
  i: Integer;
begin
  bStart.enabled:=false;
  for i := 0 to SAME_TIME-1 do
    RunThread;
end;
 
procedure TMainForm.RunThread;
var
  th:TMyThread;
begin
  inc(Started);
  th:=TMyThread.Create('URL '+inttostr(Started), ThreadTerm );
 
  Log('запущен '+th.url);
  th.Resume;
end;
 
end.

Delphi
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
unit UMyThread;
 
interface
uses Classes,ssl_openssl, httpsend;
type
  TMyThread=class(TThread)
  public
    th:TMyThread;
    URL:string;
    answer:string;
    http: THTTPSend;
    StringList: TStringList;
    procedure Execute;override;
    constructor Create(AURL:string; TermProc:TNotifyEvent);
  end;
 
implementation
uses Sysutils;
 
{ TMyThread }
 
constructor TMyThread.Create(AURL:string; TermProc:TNotifyEvent);
 
begin
  inherited Create(true);
  URL := AURL;
  FreeOnTerminate := true;
  OnTerminate := TermProc;
 
end;
 
procedure TMyThread.Execute;
var
  StringList: TStringList;
  begin
 
 
     http:=THTTPSend.Create;
     StringList:=TStringList.Create;
 
     HTTP.MimeType:='application/x-www-form-urlencoded';
     http.Timeout:=40000;
       try
 
          http.HTTPMethod('GET', 'http://ru.myip.ms');
 
               StringList.LoadFromStream(http.Document);
 
            except
            on E : Exception do begin
            URL:='     '+E.ClassName+'     '+E.Message;   end;
       end;
      Answer:=inttostr(HTTP.ResultCode);
   StringList.Free;
   http.Free;
  end;
 
end.
Не могу решить:
1. Программа все таки висит во время работы. Но если я правильно понял то только во время запуска потоков а не во время их работы.
2. Кол-во потоков сразу летит к SAME_TIME=500; и не играет роли сколько стоит MAX_THREADS=5;
В лог пишет так:
запущен URL 1
запущен URL 2
.......................
запущен URL 499
запущен URL 500
URL 32:503
URL 34:503
URL 35:503
URL 33:503
URL 36:503
===========================
Работа окончена
URL 37:503
URL 39:503
URL 41:503
URL 40:503
.....................
3. Как и где описать переменную th.paramXXX.
Спасибо.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.09.2017, 20:11
Ответы с готовыми решениями:

Про потоки
Всех с Рождеством! Вопрос к профи. Существует процедура создания потоков, у потоков есть лимит на количество. Представим себе...

Вопрос про потоки
Насколько я понял, единственный способ запустить поток — это MyThread.Resume и запустится Execute, типа как функция main. А что делать если...

Разъясните, кто продвинут в теме, про потоки
1) в процедуре, привязанной к OnTerminate, возможно распознавать, отработал поток нормально или &quot;сломался&quot;? Понятно, что можно...

37
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 16:19
Студворк — интернет-сервис помощи студентам
extrimportal,
Есть скайп?

Добавлено через 9 минут
Смотри что у меня, по моему у нас одно и тоже


Delphi
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
procedure TMainForm.SpeedButton1Click(Sender: TObject);
var
 THR_Users : TTHreadGet_Users;
 i         : integer;
 counter   : integer;
 user_ids  : String;
begin
  // Заполнение параметров
  counter := 0;
  ThreadCounter := 1;
 
  {        ПЕРЕБОР             }
  for I := Trim(edMP_Min.Text).ToInteger to Trim(edMP_Max.Text).ToInteger do
  begin
 
    if counter = 99 then
    begin
      edMP_Min.Text := i.ToString;
      counter := 0;
 
 
      ThreadCount := TrackBar1.Position;
      while ThreadCounter > ThreadCount do
      begin
        sleep(200);
        Application.ProcessMessages;
        ThreadCount := TrackBar1.Position;
      end;
 
      Label34.Caption := ThreadCounter.ToString;
      // Поток запроса
      THR_Users := TTHreadGet_Users.Create(true);
      THR_Users.FreeOnTerminate := true;
      THR_Users.OnTerminate     := OnTermenate;
 
      // Список городов, фильтр
      THR_Users.Cityes.AddStrings(memMPCityFilter.Lines);
      THR_Users.Token := NextToken; // Токен
      THR_Users.Proxy := NextPoxy;  // Прокси
      THR_Users.users_get.user_ids := user_ids; // список id пользователей
      THR_Users.Resume;
 
      inc(ThreadCounter);
      user_ids := ''
    end;
 
    user_ids := user_ids + (i.ToString+',');
    counter := counter+1;
  end;
 
end;
Добавлено через 38 секунд
Delphi
1
2
3
4
5
procedure TMainForm.OnTermenate(Sender: TObject);
begin
  Dec(ThreadCounter);
  memo2.Lines.Add((sender as TTHreadGet_Users).Error );
end;
Добавлено через 25 секунд
Здесь я ожидаю освобождение потоков
Delphi
1
2
3
4
5
6
while ThreadCounter > ThreadCount do
      begin
        sleep(200);
        Application.ProcessMessages;
        ThreadCount := TrackBar1.Position;
      end;
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
04.09.2017, 16:19
Цитата Сообщение от extrimportal Посмотреть сообщение
запускается 5000 сразу
в моем примере запускается ровно сколько сказано

в вашем коде MAX_THREADS=5 SAME_TIME=50
если посмотреть в исходную логику, то MAX_THREADS > SAME_TIME и когда количество запусков = MAX_THREADS, все остановится
у вас же изначально это условие не выполнится никогда, поэтому все повиснет этак через 3-5 тысяч стартов...
либо измените логику либо MAX_THREADS
1
04.09.2017, 16:48
 Комментарий модератора 
Цитата Сообщение от popryduhin Посмотреть сообщение
Есть скайп?
popryduhin, не надо нарушать правила форума:
4.6 Обсуждение вопросов - только в теме на форуме. Приглашения к обсуждению еще где-либо (в том числе и с помощью системы личных сообщений) запрещены, за исключением коммерческих разделов.
Предупреждение!
0
 Аватар для extrimportal
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 16:52  [ТС]
7 раз переписывал это сообщение. В результате скажу вам просто - имя константы вы выбрали очень интересно.
popryduhin вы тоже поменяйте местами колво потоков и колво записей которые нужно обработать
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 18:15
Цитата Сообщение от extrimportal Посмотреть сообщение
popryduhin вы тоже поменяйте местами колво потоков и колво записей которые нужно обработать
Что Вы имеете в виду?
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
04.09.2017, 21:01
да. возможно MAX_THREADS можно и не понять правильно
но SAME_TIME -то уж точно очевидно
0
 Аватар для extrimportal
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
05.09.2017, 01:50  [ТС]
krapotkin извините но очевидно вам, а нам далеким иногда хватит первой строки и нехватки знаний что бы пойти воооооообще в другую сторону и несмотря на это обсуждаем мы все же ваш код, как тот который из всех примеров легче всего принять и понять

Имею ввиду попробуйте поставить:
Delphi
1
2
  MAX_THREADS=100;
  SAME_TIME=2;
И посмотрите в каком нибудь снифере на результат, если запрос будет не 2+2 а например на гет запрос.
Лично я много переделал но опять через нехватку знаний вошел в тупик вот в чем:
есть запуск программы:
Delphi
1
2
3
4
5
6
7
8
9
10
procedure TMainForm.bStartClick(Sender: TObject);
var
  i: Integer;
 begin
  bStart.enabled:=false;
  urlzmemo:=0;
  finished:=0;
  for i := 0 to StrToInt(Edit6.Text) do //edit - колво потоков
   RunThread;
 end;
и есть
Delphi
1
2
3
4
5
6
procedure TMainForm.RunThread;
var
  th:TMyThread;
 begin
  inc(urlzmemo);
  th:=TMyThread.Create(Memo2.Lines[urlzmemo], ThreadTerm );
не то что бы я не знал что это плохо но я написал то что придумал.
Вопрос в том как исправить на то что бы было правильно?
Если "i" сделать переменной public - ошибка. Если не сделать то как правильно записать
Delphi
1
  th:=TMyThread.Create(Memo2.Lines[i]
п.с. Рад принять какой я далек от делфи если в результате кто нибудь подскажет решение.
Спс...

Добавлено через 9 минут
Так же интересует правильней ли будет использовать
Delphi
1
2
3
4
  
peremennaya:= StrToInt(Edit6.Text);
for i := 0 to  do peremennaya
   RunThread;
вместо
Delphi
1
2
  for i := 0 to StrToInt(Edit6.Text) do
   RunThread;
И если можно еще узнать на счет минусов использования большинства переменных в public а не private.
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
05.09.2017, 02:00
https://yadi.sk/i/g0BJE47C3MbxHZ
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
05.09.2017, 07:14
переменная должна использоваться в минимально возможной области
если она использована только внутри процедуры, то делаем ее локальной, если нет - делаем ее полем класса формы
глобальные это чаще всего просто мины отложенного действия, хотя работать конечно тоже будет.

Цитата Сообщение от extrimportal Посмотреть сообщение
Memo2.Lines[urlzmemo]
вполне себе вариант. а в чем проблема его использовать?
Цитата Сообщение от extrimportal Посмотреть сообщение
StrToInt(Edit6.Text);
это тоже не страшно, страшно то, что оно называется Edit6 а нужно бы что-то типа eThreadCount

приложение которое делает не 2*2 а в точности то же что и вы, я обычно указываю сразу при возникновении тем про потоки и интернет:
Оптимизация приложения "менеджер закачек"
0
 Аватар для extrimportal
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
06.09.2017, 10:39  [ТС]
Первое оставил, все остальное исправил на читабельные имена. Даже не замечал что у меня везде одни едиты)
Почти все готово, все перетащил, программа работает намного быстрее и не жрет память.
Осталось несколько мелочей. А именно:
с чекбоксом. Делаю так:
Delphi
1
if Proxy.Checked then th.prox:= true;
или так
Delphi
1
th.prox := Proxy.Checked;
дальше
Delphi
1
2
3
4
5
if prox then
begin
http.ProxyHost:='127.0.0.1';
http.ProxyPort:= '2222';
end;
или
Delphi
1
2
3
4
5
if prox=true then
begin
http.ProxyHost:='127.0.0.1';
http.ProxyPort:= '2222';
end;
В результате почему То, к прокси обращается только первый поток, остальные запросы к сайтам без прокси. При чем если
Delphi
1
2
3
th.poisk := poisk.text;
....
if ((Pos(poisk, StringList.Text)<>0)
то условие выполняется для каждого потока.

и проблема с паузой по примеру krapotkina с блога https://www.cyberforum.ru/blog... g4875.html
Дело в том что если все так сделать и в мемо будет список для потоков к примеру:
1 2 3 4 5 6 7
то без паузы потоки так и берут с мемо строки 1 2 3 4...
а с условием на Terminated получаются копии потоков и в результате 1 1 1 2 2 1 2 1 1 2 2 2 2 2 1 1 2 2 2 2 2 1 2 1 2 2....
кроме того после нажатия на паузу все не останавливается, а просто отдается пустой результат от потоков. то есть если запустить список из 50000 строк и нажать на стоп через секунду, то все равно надо ждать пока все потоки запустятся и отдадут пустой результат.
Можете подсказать как исправить?
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
06.09.2017, 10:54
Лучший ответ Сообщение было отмечено extrimportal как решение

Решение

пауза только для демо, ее не должно быть в рабочей программе
Цитата Сообщение от extrimportal Посмотреть сообщение
th.prox := Proxy.Checked;
Цитата Сообщение от extrimportal Посмотреть сообщение
if prox then
так правильно

про остальное - нужно видеть текущий код
нажимаете тут в тулбаре в кнопочках плюсик, потом delphi и в серединку копируете ваш текст
получается аккуратно и не простыня
1
 Аватар для extrimportal
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
06.09.2017, 12:17  [ТС]
А если допустим нужно осилить паузу или стоп в рабочей программе?
Про чекбокс, усталость сыграла роль, исправил.
Тогда вроде все, перенес все - все работает
Спасибо всем и 95% от спасибо уважаемому krapotkinу!
Не прошло и пол года как я всем выносил мозг но добился результата!
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
06.09.2017, 13:26
пауза или стоп в программе у меня в одном из примеров разобрана в том же посте

Добавлено через 54 секунды
это для вас это пауза, для программы - нет.
она делает свои дела - рисует, слушает систему и мышь и т.д.
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
10.09.2017, 16:49
extrimportal,
И все же, с помощью счетчиков ограничиваем количество потоков?
если мне предстоит 10 000 000 потоков выполнить?
0
5999 / 4574 / 1096
Регистрация: 29.08.2013
Сообщений: 28,254
Записей в блоге: 3
10.09.2017, 17:01
сделай массив потоков
заполняй его и жди когда кто-то выполнится, на его место пихай еще поток

Цитата Сообщение от popryduhin Посмотреть сообщение
10 000 000 потоков
https://www.cyberforum.ru/delphi/thread929315.html
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
10.09.2017, 18:33
Цитата Сообщение от qwertehok Посмотреть сообщение
сделай массив потоков
заполняй его и жди когда кто-то выполнится, на его место пихай еще поток
У меня есть реализация без массива, потоки создаются по очереди, результат пишется в базу.
Реализация выполнена с помощью счетчика, то есть, есть некая переменная которая увеличивает свое значение при создании потока, есть некое условие при выполнении которого основной поток приостанавливает создание дочерних потоков.

И все как бы работает и я могу указать количество потоков, так же в мониторе ресурсов видно количество потоков, так же растет нагрузка, пропорционально растет и производительность.
0
 Аватар для krapotkin
6854 / 4680 / 1465
Регистрация: 14.04.2014
Сообщений: 20,684
Записей в блоге: 21
10.09.2017, 21:36
представленная реализация и есть ограничение при помощи счетчика
что не так-то?
и потоков создается не больше чем сказано.
я не понимаю, в чем еще проблема?
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
15.09.2017, 22:21
Цитата Сообщение от krapotkin Посмотреть сообщение
представленная реализация и есть ограничение при помощи счетчика
что не так-то?
и потоков создается не больше чем сказано.
я не понимаю, в чем еще проблема?
Сам не понимаю, все работает. ))) Я думал что понадобятся какие нибудь мютексы или семафоры
Получается можно обойтись одним счетчиком в 3 строчки кода...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.09.2017, 22:21

опять про потоки
привет всем есть поток procedure TDownLoader.Execute; var http:TIdHTTP; str:TFileStream; begin //Создим класс для...

Про потоки
Если я к проге приделал два потока (Thread), один другому не будет мешать? Просто когда я в проге запускаю один поток, все норм.. как...

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

Вопрос про потоки вывода
Здравствуйте, подскажите в чём кординальная разница между использованием cerr и cout?!?!

Объясните про потоки (stream)
Здравствуйте. Помогите разобраться с потоками(не Thread, а Stream). У меня знания очень поверхностные, представляю как непрерывный поток...


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

Или воспользуйтесь поиском по форуму:
38
Ответ Создать тему
Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru