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

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

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

Author24 — интернет-сервис помощи студентам
Пробую осилить потоки по записи в блоге от 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)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.09.2017, 20:11
Ответы с готовыми решениями:

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

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

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

опять про потоки
привет всем есть поток procedure TDownLoader.Execute; var http:TIdHTTP; ...

37
Модератор
3490 / 2613 / 741
Регистрация: 19.09.2012
Сообщений: 7,974
03.09.2017, 21:40 2
Цитата Сообщение от extrimportal Посмотреть сообщение
не играет роли сколько стоит MAX_THREADS=5
А где в твоем коде это должно играть роль?
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 01:43 3
Цитата Сообщение от FIL Посмотреть сообщение
А где в твоем коде это должно играть роль?
Его код взят отсюда https://www.cyberforum.ru/blog... g4875.html
Если я не ошибаюсь

Добавлено через 15 минут
Присоединяюсь к вопросу extrimportal.

Собственно, как по простому на пальцах задать количество потоков.

Вот предположим Я хочу собрать все id в ВК но не просто собрать, а прикрепить к конкретному городу.
Что я делаю
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
procedure TMainForm.SpeedButton1Click(Sender: TObject);
var
 THR_Users : TTHreadGet_Users;
 i         : integer;
 counter   : integer;  // счетчик 
 user_ids  : String;
begin
  // Заполнение параметров
  counter := 0;
  {        ПЕРЕБОР             }
  // от 1 до 446000000 да, да вы не ослышались пол миллиарда 
  for I := Trim(edMP_Min.Text).ToInteger to Trim(edMP_Max.Text).ToInteger do
  begin
    
    // собираем порции по 99 id и кормим наш поток
    if counter = 99 then // если собрали 99 id создаем поток
    begin
      //edMP_Min.Text := i.ToString; // к делу не относится
      counter := 0; // обнуляю для следующей коллекции
 
      // Поток запроса
      THR_Users := TTHreadGet_Users.Create(true);
      THR_Users.FreeOnTerminate := true;
      // Список городов, фильтр
      
      // мои параметры
      THR_Users.Cityes.AddStrings(memMPCityFilter.Lines); // к делу не относится
      THR_Users.Token := NextToken; // Токен
      THR_Users.Proxy := NextPoxy;  // Прокси
 
      THR_Users.users_get.user_ids := user_ids; // список id пользователей   123,432,533
 
      THR_Users.Resume; // стартую
    end;
 
    user_ids := user_ids + (i.ToString+','); // здесь формирую строку запроса 
    counter := counter+1; // счетчик 
  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
procedure TTHreadGet_Users.Execute;
var
  i : integer;
  counter: integer;
  Hread: TTHreadXMLToDB;
  DataXML : string;
begin
 
  Auth.token := Token; // токен ключ
  try
 
    // здесь выполняю запрос на сервер с уже сформированными параметрами запроса
    DataXML :=  Auth.ExecuteQuery(oAuth.TMethod.USERS_GET,
                    users_get.collect_request,
                    '5.8',
                    oAuth.XML,
                    Proxy.Server,
                    Proxy.Port);
    //получил ответ в DataXML              
 
  
    // Это поток в потоке", то есть по моим размышлениям 
    // я не хочу терять время на добавление данных в базу SQLite
    // Здесь я запускаю дочерний поток для добавления в базу данных
    // и забываю про него. Думая что все будет хорошо
    Hread                 := TTHreadXMLToDB.Create(True);
    Hread.DataBasesName   := ExtractFilePath(ParamStr(0))+'ALL_VK_ID.db';
    Hread.XMLData         := DataXML; // XML данные
    Hread.Cityes.AddStrings(Cityes);
    Hread.Country         := Country;
    Hread.FreeOnTerminate := true;
    Hread.Resume;
 
    users_get.user_ids := '';
  except
 
  end;
  users_get.Free; // 
 
end;
Добавлено через 1 минуту
И получаю граблями по голове

Добавлено через 10 минут
Естественно будут прокси и токины.
Но потоки просто забивают память и проц.

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

Может как то через мютексы???.

Проясняю картину...
Будет прокси лист из 10 IP а может и больше.
Следовательно мне нужно создавать 5 потоков или даже 3
что бы они работали параллельно каждый запрос, смена IP и токена.
И минимальная задержка, максимум 40 ms

Где мне в моем коде прикрутить эти сраные мютексы или семафоры?????
как мне заставить работать только заданное количество потоков?

По предварительным расчетам, если я это реализую без дополнительных потоков, мне потребуется чуть больше месяца непрерывной работы. Задача, за счет потоков токинов и прокси вытащить все это дело на хотя бы 15 дней.

Добавлено через 6 минут
Вот что я нашел

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
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TTestThread = class(TThread)
  private
    FNum: Integer;
    procedure SynchAdd();
    procedure SynchDel();
  protected
    procedure Execute; override;
  public
    constructor Create(ANum: Integer);
  end;
 
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
const
  InitialCount = 8;
 
var
  Form1: TForm1;
  hSemaphore: THandle;
 
implementation
 
{$R *.dfm}
 
{ TTestThread }
 
constructor TTestThread.Create(ANum: Integer);
begin
  inherited Create(True);
  FreeOnTerminate:=True;
  FNum:=ANum;
  Resume;
end;
 
procedure TTestThread.Execute;
begin
  <font color="red">WaitForSingleObject(hSemaphore, INFINITE);</font>
  Synchronize(SynchAdd);
  Sleep(100+Random(100));
  Synchronize(SynchDel);
  <font color="red">ReleaseSemaphore(hSemaphore, 1, nil);</font>
end;
 
procedure TTestThread.SynchAdd;
begin
  Form1.Tag:=Form1.Tag+1;
  Form1.Label1.Caption:=IntToStr(Form1.Tag);
end;
 
procedure TTestThread.SynchDel;
begin
  Form1.Tag:=Form1.Tag-1;
  Form1.Label1.Caption:=IntToStr(Form1.Tag);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i:=1 to 100 do TTestThread.Create(i);
end;
 
<font color="Red">initialization
  hSemaphore:=CreateSemaphore(nil, InitialCount, InitialCount, nil);
 
finalization
  CloseHandle(hSemaphore);</font>
 
end.
Все ровно потоки создаются непрерывно и их количество постоянно растет.
Даже пришлось компьютер из розетки выключать
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 09:41  [ТС] 4
Это просто орфографическая ошибка. Будет ли
Delphi
1
2
if Started<  MAX_THREADS then
    RunThread;
или
Delphi
1
2
if Started<10 then
    RunThread;
Все равно потоков запустится ровно SAME_TIME. И во время их запуска все висит, во время получения ответа от них уже не висит.
0
D1973
04.09.2017, 10:11
  #5

Не по теме:

Цитата Сообщение от popryduhin Посмотреть сообщение
Даже пришлось компьютер из розетки выключать
и RESET не помог? Беда-а!!! :D

1
Модератор
3490 / 2613 / 741
Регистрация: 19.09.2012
Сообщений: 7,974
04.09.2017, 12:28 6
Цитата Сообщение от extrimportal Посмотреть сообщение
Все равно потоков запустится ровно SAME_TIME.
С какого перепугу их должно запускаться меньше?
Ты знаком с принципами работы цикла for?
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 12:39  [ТС] 7
Да знаком. Но не в том дело. Дело в том что не работает условие
Delphi
1
2
 if Started<10 then
    RunThread;
Запускается сразу кол-во равное SAME_TIME. Как же запускать нужное кол-во потоков?
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 13:52 8
extrimportal,
Есть какое нибудь решение?
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 14:07  [ТС] 9
Перебираю литературу. Может когда то сам дойду)
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 14:11 10
Цитата Сообщение от extrimportal Посмотреть сообщение
Перебираю литературу. Может когда то сам дойду)
Сейчас опытным путем иду по дороге мютексов

Идея такая

Я создаю массив мютексов N количество, в соответствии с нужным количеством потоков
в событии OnTermenate я удаляю те мютексы которые я передал потоку и создаю новый мютекс на его место и соответственно создаю очередной поток
0
5786 / 4528 / 1431
Регистрация: 14.04.2014
Сообщений: 20,157
Записей в блоге: 20
04.09.2017, 14:27 11
тут чисто в мелочах дьявол-то ))
пример же демонстрационный. чтобы легко понимался...
проблема тут конкретно в том, что работа с логом занимает в нем гораздо большее время, чем работа самих потоков
если поставить в Execute Sleep(5000+Random(5000)) то мы увидим, что программа "оживает". т.к. пока потоки работают и не обращаются к основному потоку, программа занимается перерисовкой и ответом на события мыши и клавиатуры
и в реальном приложении приходится учитывать и такие засады )

мемо - крайне тормозной компонент. если в нем 3-5 тысяч строк, то с гарантией 80% времени ваша программа будет тратить на его заполнение ))) я уже обжигался на этом))
если вместо мемо просто взять PaintBox и на него выводить StringList, скорость вырастет раз в 100 )
можно придумать и другие способы.

Добавлено через 35 секунд
не нужно плодить сущности без необходимости )

Добавлено через 4 минуты
Цитата Сообщение от popryduhin Посмотреть сообщение
Я хочу собрать все id в ВК
Цитата Сообщение от popryduhin Посмотреть сообщение
сервер Вк не доволен моими действиями
кажется я знаю почему ))
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 14:35 12
Цитата Сообщение от krapotkin Посмотреть сообщение
кажется я знаю почему ))
Я тоже ))) Задача сгладить это
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 14:42  [ТС] 13
Я бы согласился если бы дело было в 2+2, но когда дело в гет запросе и вылетает 500 запросов к сайту сразу, то по моему здесь что то другое.
И могли бы вы объяснить что нибудь на счет "Как и где описать переменную th.paramXXX."
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 14:47 14
Зная что несу чушь

Delphi
1
2
3
4
5
6
      ThreadCount := TrackBar1.Position;
      while ThreadCounter > ThreadCount do
      begin
        sleep(200);
        Application.ProcessMessages;
      end;
ThreadCounter это счетчик
ThreadCount это количество потоков

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
      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); // увеличиваю счетчик

в

Delphi
1
2
3
4
procedure TMainForm.OnTermenate(Sender: TObject);
begin
  Dec(ThreadCounter); уменьшаю счетчик
end;
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 15:04  [ТС] 15
Прочитайте про Application.ProcessMessages; у krapotkin
п.с. Как на меня то семафоры и мютексы слишком для такой простой задачи как получить хтмл по урл.
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 15:09 16
Цитата Сообщение от extrimportal Посмотреть сообщение
Прочитайте про Application.ProcessMessages; у krapotkin
да. Почитаю.

Delphi
1
2
3
4
5
6
ThreadCount := TrackBar1.Position;
      while ThreadCounter > ThreadCount do
      begin
        sleep(200); // c этой строчкой проц не греется
        Application.ProcessMessages;
      end;
Добавлено через 48 секунд
Тогда как же все таки задать количество потоков????
Мы все ходим вокруг да около.

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

Добавлено через 48 секунд
Мне наверное проще будет понять это схематично и на пальцах как ребенку.
0
5786 / 4528 / 1431
Регистрация: 14.04.2014
Сообщений: 20,157
Записей в блоге: 20
04.09.2017, 15:18 17
Цитата Сообщение от extrimportal Посмотреть сообщение
th.paramXXX
видно же по записи, что это поле переменной th, следовательно описывается в классе потока
Delphi
1
2
3
4
5
6
7
TMyThread=class(TThread)
...
public
  ParamXXX:integer;
  ParamYYY:string;
....
end;
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 15:39  [ТС] 18
Не ну тут реально ступил, вообще смотрел в другую сторону
popryduhin есть вариант который работает, но сам кривой и как раз его и пытаюсь переписать по правилам. могу поделиться пищей для размышлений.
krapotkin у вас есть мысль почему у нас даже если выставить 2 потоки и общее количество 5000 записей для обработки. запускается 5000 сразу? Смотрел через хттпанализер, и это точно так.
0
30 / 26 / 8
Регистрация: 17.09.2015
Сообщений: 498
Записей в блоге: 6
04.09.2017, 15:52 19
extrimportal,
Было бы хорошо если бы Вы выложили решение здесь, в этой ветке.

Добавлено через 7 минут
Сейчас попробовал свой костыль. Вроде ка бы работает, удается контролировать количество через счетчики.
Но есть сомнения, на счет ошибок, что если произойдет ошибка в самом потоке
сработает ли событие OnTermenate которая вычитает количество ??

Добавлено через 1 минуту
Цитата Сообщение от extrimportal Посмотреть сообщение
krapotkin у вас есть мысль почему у нас даже если выставить 2 потоки и общее количество 5000 записей для обработки. запускается 5000 сразу? Смотрел через хттпанализер, и это точно так
У indy свои потоки тоже есть
0
0 / 0 / 0
Регистрация: 28.02.2015
Сообщений: 83
04.09.2017, 16:07  [ТС] 20
На счет инди не понял.
Вот так сделали мне. Я хочу переписать что бы работало нормально. Тем более мне так сделали что идет утечка памяти, и что не сделай в районе 1400 потока аут оф мемори.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TForm1.Button16Click(Sender: TObject);
for j := 0 to Memo1.Lines.Count-1 do
     begin
          while pauses=true do pause(1000);
          MyThread:= TMyThread.Create(Memo1.Lines[j]);
          MyThread.Priority:=tpNormal;
          potoki:=potoki+1;
          while StrToInt(form1.Edit1.Text)=potoki do begin pause(1000); application.ProcessMessages; end;
          application.ProcessMessages;
     end;
 
procedure TMyThread.Execute;
бла бла бла
 
 potoki:=potoki-1;
end;
Сейчас начал все перекидывать с старой программы, идет вроде ничего только с кол-вом потоков решить надо.
0
04.09.2017, 16:07
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.09.2017, 16:07
Помогаю со студенческими работами здесь

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

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

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

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

Ищу литературу про потоки
Дайте, пожалуйста, нормальный ресурс где будет хорошо объяснено про потоки, мьютексы, семантика и...

Потоки, семафор в задаче про корабли
Здравствуйте. Задание такое: Порт. Корабли заходят в порт для разгрузки/загрузки контейнеров....


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru