Kilkanaście takich samych wątków

0

Będę musiał w programie utworzyć nawet 200 wątków. Każdy ma robić to samo == kod jest jeden.
Czy taki kod będzie ok?

DWORD WINAPI Thread(PVOID pVoid)
{
    while (true) {
        //robi coś
    }
}
for (int i = 0; i < 200; i++) CreateThread(0,0,Thread,0,0,0);

@Edit
Sprawdziłem i działa.

1

Jeżeli masz 200 wątków to coś jest nie halo. Może pomyśl nad pulą wątków. Czyli tworzysz powiedzmy 32 wątki, i te 32 wątki obrabiają te 200 zadań. Jak tylko wątek skończył jedno zadanie to sprawdza czy jest jeszcze coś do wykonania: jak jest to bierze kolejne, jak NIE MA to się kończy.

0

Jednak rozwiązałem to lekko inaczej:
Pobieram ilość rdzeni u użytkownika i mnożę razy 4. Myślę, że to będzie wystarczająco efektowne ;)

0

efektYwne chyba miałeś na myśli. po co chcesz mieć więcej wątków, niż rdzeni, które mogą je obsłużyć? ma to sens tylko wtedy, kiedy wątki na coś czekają, ale wtedy robi się to inaczej - kolejne pule wątków i dodatkowe kolejki danych plus synchronizacja, żeby żadna kolejka się nie zatkała. owszem, komplikuje to algorytm, ale umożliwia bardziej wydajną pracę.

0
_13th_Dragon napisał(a)

Po zakończeniu obróbki zadania, wątek tak czy owak czeka na kolejne zadanie, więc ma sens dwa razy więcej niż rdzeni. Jeżeli zaś zadania są krótkie to więcej wątków czeka na przydzielenie zadania przez wątek rozdzielający. Matematyczna minimalizacja tego daje wynik: wątków ma być Pi (3.14) na rdzeń. No i teraz kwestia zaokrąglenia, w górę czy w dół, po mnożeniu przez ilość rdzeni czy przed. Jako ciekawostka: http://msdn.microsoft.com/pl-pl/library/ms187024%28v=sql.105%29.aspx

moim zdaniem wątek po skończeniu pracy na nic nie czeka. jeśli jest dostępne zadanie, to je od razu bierze. operacja pobrania jest zabezpieczona semaforem czy sekcją krytyczną, ale pobranie z kolejki trwa bardzo krótko i to nie blokuje puli. żaden tam wątek rozdzielający; przecież jest do niczego niepotrzebny. nie rozumiem też, w jaki sposób dwukrotne zwiększenie liczby wątków poprawi wydajność, przecież to dwa razy więcej przełączeń kontekstu, które są dość kosztowne. być może czegoś nie rozumiem, jestem z wykształcenia elektronikiem, a nie programistą i być może brakuje mi teorii. możesz wyjaśnić mi skąd się biorą rozbieżności między moim chłopskim rozumem a tym, co piszesz?

wydaje mi się, że mssql ma dużo wątków, bo robią mnóstwo operacji i/o i wtedy śpią.

0
ŁF napisał(a):

moim zdaniem wątek po skończeniu pracy na nic nie czeka. jeśli jest dostępne zadanie, to je od razu bierze. operacja pobrania jest zabezpieczona semaforem czy sekcją krytyczną, ale pobranie z kolejki trwa bardzo krótko i to nie blokuje puli.
Czyli czeka na ten semafor/synchronizacje.

ŁF napisał(a):

nie rozumiem też, w jaki sposób dwukrotne zwiększenie liczby wątków poprawi wydajność, przecież to dwa razy więcej przełączeń kontekstu, które są dość kosztowne.
Dopóki wątek czeka na semafor on nie zabiera czasu ani nie ma przełączenia kontekstu na niego.

ŁF napisał(a):

wydaje mi się, że mssql ma dużo wątków, bo robią mnóstwo operacji i/o i wtedy śpią.
Prawie dobrze ci się wydaje. Oni nie śpią tylko czekają na dostęp do współdzielonego pliku czyli czekają na semaforze, owszem to jest prawie jak śpią, różnica polega na tym że nie ma z góry określonego czasu.

0
_13th_Dragon napisał(a):
ŁF napisał(a):

moim zdaniem wątek po skończeniu pracy na nic nie czeka. jeśli jest dostępne zadanie, to je od razu bierze. operacja pobrania jest zabezpieczona semaforem czy sekcją krytyczną, ale pobranie z kolejki trwa bardzo krótko i to nie blokuje puli.
Czyli czeka na ten semafor/synchronizacje.

doh, jeśli jest co robić to przecież to tylko kilka cykli procka, bez znaczenia przy miliardach cykli pracy.

_13th_Dragon napisał(a):
ŁF napisał(a):

wydaje mi się, że mssql ma dużo wątków, bo robią mnóstwo operacji i/o i wtedy śpią.
Prawie dobrze ci się wydaje. Oni nie śpią tylko czekają na dostęp do współdzielonego pliku czyli czekają na semaforze, owszem to jest prawie jak śpią, różnica polega na tym że nie ma z góry określonego czasu.
</quote>
żadna różnica. jeśli nie wiesz o której się obudzisz to śpisz inaczej niż wtedy, kiedy nastawisz budzik? ;-) a tak serio - fakt, stan wątku jest trochę inny, ale sprowadza się to do tego samego - wątek czeka, nie wykonuje pracy, nie obciąża procesora. a jak już czepiamy się szczegółów, to wątki mssql czekają na multum rzeczy, nie tylko na dostęp do pliku.

dalej czekam na wyjaśnienie dlaczego więcej wątków niż jest procesorów miałoby przyspieszyć działanie kodu (przy założeniu, że wątki czekają tylko na dane i na nic innego).

0
ŁF napisał(a):

dalej czekam na wyjaśnienie dlaczego więcej wątków niż jest procesorów miałoby przyspieszyć działanie kodu (przy założeniu, że wątki czekają tylko na dane i na nic innego).
I nie zrozumiesz tego, dopóki nie zrozumiesz że jak masz trzy wątki pisarzy (schemat pisarz czytelnik) to muszą oni ustawić się w kolejce nie robiąc nic a nic jednocześnie i nic na to nie poradzisz. Nawet pobranie zadania może być całkiem długotrwałe, np zadania zapisywane do bazy danych w postaci wiersza w tablice, teraz opracuj bezpieczne wielowątkowe pobieranie danych z tej bazy i zaznaczenie wierszy w jednym z pół statusami: Oczekuje, Wtoku, Gotowe. Jak dodasz do tego że wątki nie koniecznie z tego samego programu ba nawet nie z tego samego komputera to czas oczekiwania jeszcze bardziej się wydłuża.

0

jak sobie wymyślę taki schemat pobierania zadań, który zajmie dużo czasu, to może się okazać, że i tysiąc wątków to za mało, żeby w pełni obciążyć procesor, przecież to oczywiste.
czytasz wybiórczo - napisałem, że pobranie z kolejki zajmie kilka cykli procesora, bo jest stworzone WYDAJNIE. niech to będzie nawet kilka tysięcy czy kilka miliardów cykli procesora - jeśli wykonanie zadanie zajmuje kilka minut to i tak jest to pomijalne. a problem pisarzy i czytelników jest cokolwiek akademicki, znasz jakąkolwiek aplikację, w której ktoś musiał z tym sobie radzić, bo mu wydajność przetwarzania danych znacząco spadła?

_13th_Dragon napisał(a):

I nie zrozumiesz tego, dopóki nie zrozumiesz że jak masz trzy wątki pisarzy (schemat pisarz czytelnik) to muszą oni ustawić się w kolejce nie robiąc nic a nic jednocześnie i nic na to nie poradzisz.

smutne. ostatni musi czekać aż kilkanaście cykli. zestarzeje się, a jeśli wziąć pod uwagę, że w kolejce czekają jeszcze czytelnicy, to niewątpliwie umrze ze starości. człowieku, jak/jakie Ty piszesz aplikacje, że masz takie dziwne problemy?

0

Przecież podałem ci linka z przykładem, sądzisz że oni to z palca wyssali? To to napisz do nich i się pokłóć o to jakie systemy oni piszą. Na wszelki wypadek podaje jeszcze raz: http://msdn.microsoft.com/pl-pl/library/ms187024%28v=sql.105%29.aspx Dla większości systemów pisanych przeze mnie optymalne Pi()*IlośćRdzeni dla takiego w który ty się uparłeś nie widząc innych możliwości zastosowania wątków wystarczy IlośćRdzeni+1.

0

czytasz bez zrozumienia. link dotyczy czegoś zupełnie innego. kilka razy podkreślałem, że chodzi o sytuację, kiedy wątek pracuje, a nie czeka, jakoś nie dotarło to do Ciebie. to chyba oczywiste, że jeśli wątek często/długo na coś czeka, to warto mieć więcej wątków niż rdzeni/procesorów i wcale niekoniecznie w proporcji pi, co widać w "przykładzie", który podałeś.

jestem ciekaw ile i jakie to wielowątkowe systemy tworzysz :-) ja z większych rzeczy tego typu mam za sobą jeden projekt - rozproszony wielowątkowy i wieloprocesowy transcoder do filmów i audio. rok pracy. a Ty?

i na koniec - jeśli piszesz do kogoś na ty, to pisz to wielką literą.

1

Bezsensowna dyskusja o szczegolach, ktorych do konca nie znacie. Przyklad:

Dopóki wątek czeka na semafor on nie zabiera czasu ani nie ma przełączenia kontekstu na niego.

Przeciez to zalezy co to za semafor jest - rownie dobrze semafor uzyty w mssql moze przez jakis czas wykorzystywac aktywne czekanie wiec watek oczekujacy na takim semaforze moze miec przelaczony kontekst.

Jezeli chodzi o optymalna liczbe watkow to jedyny sposob zeby ja ustalic to po prostu zrobic testy wydajnosciowe dla roznych ilosci watkow i wybrac taka liczbe ktora daje najlepszy czas dla wykonywanego zadania. Reguly w stylu dwa razy tyle watkow ile procesorow, lub inne sa dobre na start ale nie zastapia testow.

0

W nawiązaniu do ilości wątków na ilość procesorów, popełniłem taki test dla jednego z projektów.

#include <pthread.h>
#include <iostream>
using namespace std;

const unsigned ColCount=72;
const unsigned ThreadCount=72; // nie może być większa niż ColCount
char Data[ColCount+1]={0};

void ctrlC(int);

class thread
  {
   private:
   typedef void (thread::*Job)();
   Job job;
   unsigned y,Shift;
   pthread_t handle;
   pthread_cond_t resume;
   pthread_mutex_t wakeup;
   static pthread_cond_t *alldone;
   static pthread_mutex_t *stopwait;
   static unsigned Done;
   static void *runthread(void *ptr);
   void *run();
   void execute(Job ajob,unsigned ay,unsigned aShift);
   void nothing();
   void square();
   void multiply();
   public:
   thread();
   ~thread();
   void dosquare(unsigned y,unsigned Shift) { execute(&thread::square,y,Shift); }
   void domultiply(unsigned y,unsigned Shift) { execute(&thread::multiply,y,Shift); }
   static unsigned done() { return Done; }
   static void reset(unsigned Count) { Done=Count; }
   static void wait()
     {
      pthread_mutex_lock(stopwait);
      if(Done) pthread_cond_wait(alldone,stopwait);
      pthread_mutex_unlock(stopwait);
      if(Done) throw "FAIL SYGNAL";
     }
   private:
   static unsigned doneinit()
     {
      static pthread_cond_t init_alldone;
      static pthread_mutex_t init_stopwait;
      static bool needinit=true;
      if(needinit)
        {
         pthread_mutex_init(&init_stopwait,0);
         stopwait=&init_stopwait;
         pthread_cond_init(&init_alldone,0);
         alldone=&init_alldone;
         needinit=false;
        }
      return 0;
     }
   static void report()
     {
      pthread_mutex_lock(stopwait);
      if(!--Done) pthread_cond_signal(alldone);
      pthread_mutex_unlock(stopwait);
     }
  };
pthread_cond_t *thread::alldone=0;
pthread_mutex_t *thread::stopwait=0;
unsigned thread::Done=thread::doneinit();

thread::thread():job(&thread::nothing),y(ColCount-1),Shift(0)
  {
   pthread_mutex_init(&wakeup,0);
   pthread_cond_init(&resume,0);
   pthread_create(&handle,0,runthread,this);
  }

thread::~thread()
  {
   execute(0,ColCount,0);
   void *ret;
   pthread_join(handle,&ret);
   pthread_cond_destroy(&resume);
   pthread_mutex_destroy(&wakeup);
  }

void *thread::runthread(void *ptr)
  {
   return ((thread*)ptr)->run(); 
  }

void *thread::run()
  {
   while(job)
     {
      pthread_mutex_lock(&wakeup);
      while(y<ColCount)
        {
         (this->*job)();
         report();
         y+=ThreadCount;
        }
      pthread_cond_wait(&resume,&wakeup);
      pthread_mutex_unlock(&wakeup);
     }
   return this;
  }

void thread::execute(thread::Job ajob,unsigned ay,unsigned aShift)
  {
   pthread_mutex_lock(&wakeup);
   job=ajob;
   y=ay;
   Shift=aShift;
   pthread_cond_signal(&resume);
   pthread_mutex_unlock(&wakeup);
  }

void thread::nothing()
  {
  }

void thread::square()
  {
   //Sleep(10+rand()%100);
   Data[y]=(Data[y]+1-'A')%26+'A';
   //Sleep(10+rand()%100);
  }

void thread::multiply()
  {
   //Sleep(10+rand()%100);
   Data[y]=(Data[y]+25-'A')%26+'A';
   //Sleep(10+rand()%100);
  }

thread *once()
  {
   static thread TH[ThreadCount];
   return TH;
  }

int main()
  {
   srand(time(0));
   thread::reset(ThreadCount);
   thread *TH=once();
   memset(Data,'A',ColCount);
   thread::wait();
   while(true)
     {
      for(int i=0;i<26;++i)
        {
         thread::reset(ColCount);
         for(unsigned y=0;y<ThreadCount;++y)
           {
            TH[y].dosquare(y,i);
           }
         thread::wait();
         cout<<Data<<endl;
        }
      for(int i=0;i<26;++i)
        {
         thread::reset(ColCount);
         for(unsigned y=0;y<ThreadCount;++y)
           {
            TH[y].domultiply(y,i);
           }
         thread::wait();
         cout<<Data<<endl;
        }
     }
   cin.sync();cin.get();
   return 0;
  }

Proszę zauważyć że przy tak krótkich zadaniach maksymalna wydajność jest przy 72 wątkach (niezależnie od tego ile mamy procesorów) czyli dokładnie tyle ile trzeba zrobić zadań. Co ciekawe jak odkomentujemy te Sleep'y to sytuacja bardzo się zmienia.

0
ŁF napisał(a):

napisałem, że pobranie z kolejki zajmie kilka cykli procesora, bo jest stworzone WYDAJNIE. niech to będzie nawet kilka tysięcy czy kilka miliardów cykli procesora - jeśli wykonanie zadanie zajmuje kilka minut to i tak jest to pomijalne.

0

No właśnie jeżeli średnio wątek trwa długo to mamy sytuacje OptymalnaIlośćWątków=IlośćProcesorów natomiast jak średni czas wątku się zmniejsza to lepsze okazują się te rozwiązania z bardzo dużą ilością wątków. Tak jak w podanym przeze mnie linku dotyczącego baz danych, średnie oczekiwany czas wątków musi być bardzo mały (inaczej baza danych jest kiepska) co powoduje potrzebę dużej ilości wątków.

0

ooo, nareszcie wypowiedź, z którą się całkowicie zgadzam. peace!

1 użytkowników online, w tym zalogowanych: 0, gości: 1