|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Многопоточность с ограниченным количеством потоков
Уважаемые программисты, направьте на путь.
Есть список URL в TStringList. Я забираю данные с этих страниц к себе в базу. Многопоточность создать удалось, но куча косяков. Среди них не могу по-челевечески решить следующий вопрос: Я хочу устанавливать количество одновременно работающих потоков, например 8, а записей пусть 100. Как мне это верно организовать? Т.е. мне нужно отслеживать количество работающих потоков, как только какие-то освободились, подгружать новые? Код:
unit unit1; procedure TF_Irr.GetCache(SL:TStringList; threads:integer); var i,j,thrds,len:integer; a: array of TMyThread1; begin alive:=0; //живые потоки i:=0; thrds:=threads; //количество мной установленных потоков len:=SL.Count; //А ДАЛЬШЕ - МОЯ ФАНТАЗИЯ, КОТОРАЯ, Я УВЕРЕН, ДОЛЖНА ПРОЩЕ РЕШАТЬСЯ SetLength(a,len); repeat if i<=len-1 then begin if (len-i)<thrds then begin thrds:=len-i; alive:=0; end; if alive<thrds then begin for j:=i to (thrds-alive-1+i) do begin a[j]:=TMyThread1.Create(true,SL[i]); a[j].Resume; //запускаем процедуру загрузки данных inc(i); end; end else a[i-1].WaitFor; end; until i>len-1; end; /////////////////////////////////////// unit thread; constructor TMyThread1.Create(CreateSuspended: boolean; AURL: string); begin inherited Create(CreateSuspended); FURL:=AURL; InterlockedIncrement(alive); Priority:=tpHigher; //FreeOnTerminate:=true; OnTerminate:=ThreadExit; //Resume; end; procedure TMyThread1.ThreadExit(Sender: TObject); begin InterlockedDecrement(alive); synchronize(ShowAlive); end; procedure TMyThread1.Execute; var s,ch: string; i: integer; inStream: TMemoryStream; E: Exception; idHTTP: TIdHTTP; idCompress:TIdCompressorZLib; begin //код процедуры synchronize(ShowResult); Terminate; end; procedure TMyThread1.ShowResult; begin //куда-нить записываю данные, пусть в memo end; На одном из форумов получил ответ: Цитата:
Подскажите наиболее верное решение. Я только начал знакомиться с потоками. Заранее огромное спасибо |
#2
|
|||
|
|||
Тебе в сторону CriticalSection.
Собственно, тебе надо сделать следующую вещь (как бы делал я): 1. Делаем объект-одиночку для списка адресов. 2. Делаем объект пула потоков. Можно помотреть, по-моему в Indy уже такой есть. Его задача контролировать сам список потоков. 3. Делаем класс потоков. В своем состоянии ничего не делания он должен каждые по-секунды, например, просыаться и спрашивать у объекта одиночки - есть ли задания для него. Если нет - то засыпаем опять. Получения задания нужно сделать через CriticalSection, что не даст нескольким потокам вытащить один и тот же адрес. В этом месте они просто встанут в очередь. 4. Потоки можно создать сразу и уничтожить при закрытии программы. Это простой вариант. Есть еще сложный, когда потоки будут извещать о том, что им делать нечего и умирать, а какой-нить менеджер будет из создавать и раздавать задания. Вопрос - нужно ли это. |
#3
|
||||
|
||||
Цитата:
Код:
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 WaitForSingleObject(hSemaphore, INFINITE); Synchronize(SynchAdd); Sleep(100+Random(100)); Synchronize(SynchDel); ReleaseSemaphore(hSemaphore, 1, nil); 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; initialization hSemaphore:=CreateSemaphore(nil, InitialCount, InitialCount, nil); finalization CloseHandle(hSemaphore); end. http://data.cod.ru/141194 Пишу программы за еду. __________________ Последний раз редактировалось NumLock, 01.02.2012 в 10:02. |
Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
bulldog (30.11.2012)
|
#4
|
|||
|
|||
Спасибо. Буду пробовать/кумекать
|
#5
|
|||
|
|||
NumLock: MaximumCount = 8 - константа. Пожскажи, а просто, как переменную я разве не могу задать?
|
#6
|
||||
|
||||
Можешь,
Код:
var MaximumCount : Integer = 8; Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#7
|
||||
|
||||
Код:
hSemaphore:=CreateSemaphore(nil, 8, 8, nil); Пишу программы за еду. __________________ |
Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
bulldog (30.11.2012)
|
#8
|
|||
|
|||
NumLock, а можете подсказать, что делать если записей ооочень много? столько потоков одновременно наметво вешают систему
|
#9
|
||||
|
||||
пересмотреть алгоритм!
Пишу программы за еду. __________________ |
Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
bulldog (30.11.2012)
|