Post by Maciej SobczakI tu płynnie przechodzimy do pytania o to, gdzie jest właściwy poziom abstrakcji. Bo Ty chciałbyś, żeby w bibliotece HTTP była abstrakcja wątków na wypadek portowania na inną platformę. A ja pytam, dlaczego cały serwer HTTP nie miałby być tą abstrakcją, z różnymi implementacjami na różne platformy?
Ależ oczywiscie, przecież normalne jest że bibliteka zaczyna się od
czegoś w rodzaju:
IHttpServer* Factory::createServer(
getTcpStreamsAbstractFactory()
, getAbstractThreadsPoolFactory()
, ConcurencyModel::Threaded
);
To ja decyduje jakie abstrakcjie to TCP i wątków dostarcze. Moge
dostarczyć Twoje np. oparte o std::, o ile je napiszesz, ale mogę
dostarczyć moje oparte o gołe FreeRTOS albo własny scheduler. Ja
decyduje czy chcę wątki a jak chce to jakie, nic o tym nie musisz wiedzieć.
Post by Maciej SobczakCała ta biblioteka ma dokładnie 2 pliki .cpp. Słownie: dwa. Plus 2 headery do nich. I działa na Lin/Mac/Win. Dołożenie do niej abstrakcji na okoliczność egzotycznych platform wbudowanych z pół-wątkami i dziwacznymi stosami TCP spowodowałoby, że tych plików byłoby 10. Albo 30.
Co złego w plikach ;) Myślałem że czasy MSDOSa słusznie minęły :)
Post by Maciej SobczakI nawet nie wiem, jaka jest realna nisza rynkowa z takimi potrzebami i czy ona w ogóle jest.
Nie ma. Sporo piszesz jeszcze jedną biblioteczkę do http to chyba nie po
to aby zarabiać. Obecnośc niszy nie ma znaczenia.
Post by Maciej SobczakBo nisza na wersję 1.0 jest na pewno, bo w szczególności ja sam tego użyję. Natomiast te abstrakcje rozwiązałyby problem ludzi o których nawet nie wiem, czy istnieją.
Jeśli nie zaimplementujesz jakiegoś ficzera to ludzie potrzebujący go,
nie wezmą tej bibliteki. Ponieważ nie napiszą Ci że coś jest potrzebne
będziesz miał fałszywe przeswiadczenie że nikomu to nie jest potrzebne.
Taki przykład: embedowanie engine tcl-a do własnego kodu powoduje ze do
dyspozycji masz *tylko* blokującą funkcję która wygląda tak:
Tcl::doEverything()
{
while( finished( ) )
Private::doSomething();
}
Najlepsze że ta funkcja pojawiła się po tym jak wypruli sobie żyły aby
zrobic stackless wersję. Efektem czego cały sens stackless (ja
kontroluje stack) został zaprzepaszczony bo jakiś miszczu założył "komu
to potrzebne, dajmy mu pętlę, będzie miał łatwiej" i nie da się z nigo
korzystać jak ze stackless. Interweniowałem na grupie, czy nie mogli by
udostepnić doSomething() ale dowiedziałem się że "na co to komu". Teraz
widzisz? Jak nie ma ficzera to do czasu aż nie pojawi się jakiś
pieniacz, jak ja, autorzy mogą żyć w błednym przekonaniu że "na co to
komu". A akurat mi to jest potrzebne (i emuluje to przez boost::context,
innymi słowy używam armaty na muchy).
Post by Maciej SobczakA nie lepiej poczekać, aż ktoś *realnie* zgłosi taką potrzebę i wtedy zrobić port tych dwóch plików z zachowaniem API całego serwera HTTP?
Jeśli prawidłowych abstrakcji nie zrobi się odpowiednio wcześnie to
potem ciągnięcie koncepcji "no ale przecież są wątki" staje się
nierefaktorowalne, bo tego typu koncepcje przeciekają do api usera w
postaci jakiś zdeformowanych wzorców uzycia pasujacych do wątków ale nie
pasujacych do event based. Potem tylko pozostaje powiedzieć "sorry" i tyle.
Post by Maciej SobczakTak, będzie parę linijek zduplikowanych. Ale przekonaj mnie teraz, że koszt tych wszystkich abstrakcji jest mniejszy.
Koszt abstrakcji jest kosztem początkowym. Jeśli potrzeba pojawia się
później (a w zasadzie, jeśli autor po prostu nie zakładał że ona
istnieje na poczatku) to koszt jest wyższy z powodu długu
technologicznego który rośnie wraz z każda linią napisaną bez
prawidłowych abstrakcji.
Post by Maciej SobczakPost by hebyTo tylko łatwo w teorii, w normalnych systemach "podmienianie"
std::whatever to jest *gruby* hacking...
Ale przecież nie pisałeś o normalnych systemach. :-)
Piszę o róznych rzeczach. Gdybym pisał na FreeRTOS to ogólnie nie uzyje
czegokolwiek z std::thread z racji braku implementacji std::. Jeśli
piszę jako embedded server w środku mojej aplikacji to mimo posiadania
std::threads mogę, z jakiejś przyczyny, nie chcieć ich użyć. Na przykład
z powodu tego że threads powodują spory spadek wydajności, albo np. z
powodu tego że mam system RT i nie mogę zakładać że jakieś przypadkowe
wątki uszkadzają mi cache latency albo przerwią ważny algorytm RealTime,
itd itp.
Post by Maciej SobczakNa normalnych to wszystko działa out-of-the-box i nie trzeba nic hacking.
Wtedy można się zastanowić dlaczego miałbym brać takie *coś* zamiast
QtHttpServer?
Post by Maciej SobczakPost by hebyNiby tak, ale znowu: co dziwnego w tym że robisz własną abstrakcję do
"ich" abstrakcji?
A co dziwnego w tym, że ich nie robię i zamiast tego proponuję minimalne rozwiązanie dla 99.9% potencjalnych odbiorców?
Nic. Tak wybrałeś. To nie są zarzuty i nie nakłaniam Cie do zmiany.
Prosiłeś o uwagi, nie miej pretensji że ktoś je zgłasza i argumentuje
prowadząc normalną dyskusję. Ja nic nie zarzucam, ale skoro jest
przestrzeń do dyskutowania to przecież usenet po to powstał
Post by Maciej SobczakPost by heby*wszystkie* interfejsy GUI jakie istnieją w sensownym zastosowaniu są
event-based czyli takie coroutines/cooperative.
To ciekawa uwaga. W tej bibliotece nie ma na wierzchu niczego podobnego do kolejki, a co za tym idzie nie zmusza się użytkownika do kręcenia własną pętlą zdarzeń.
Ale zmusza to czekania na threads::join oraz używania w kodzie który
jest GUIoty synchroniacji między wątkami bo callbacki są threaded.
Innymi słowy Twoja bibliteka wymusiła pojawienie się w kodzie GUI
synchronizacji która tam jest zbędna.
Coroutines -> musisz kręcić jakimś server->next()
Wątki -> musisz synchronizować callbacki z i do bibloteki.
Ani jedno ani drugie nie jest lepsze. Ale mają coroutines można dodać
wątki w trywialny sposób. Mając wątki można, ale to bardzo naciągane,
próbować robić kieskie coroutines z masą hazardów i kiepskim unit
testowaniem.
Przy czym to moja opinia. Opieram ją o pewne doświadczenia które trudno
nazwać obiektywnymi.
Post by Maciej SobczakPod tym względem ta biblioteka bardziej przypomina lekki framework komunikacyjny, niż typowy framework GUI.
To nie ma znaczenia co przypomina. Jeśli używa wątków i ma callbacki to
warstwa poniżej musi synchronizować dostęp do zasobów.
Innymi słowy programista GUI będzie musiał odizolować Twoją biblotekę
masa wrapperów które ukryją wątkowość Twojej bibloteki jeśli nie chce
aby mutexy rozlazły się po całym kodzie GUI.
Post by Maciej SobczakCzyli zamiast odpowiadać na pytanie jak zrobić GUI, odpowiadamy na pytanie, jak zrobić komunikację z tym czymś co robi GUI[*].
GUI (natywne) nie lubi jeśli ktoś komunikuje się z nim przez wątki. To
powoduje masę problemów ponieważ wszystkie najważniejsze frameworki
GUIowe na normalne maszyny zakładają model jednowątkowy na poziomi API
systemowego. Więc jeśli budujesz apliakcję na komputer w którym jest GUI
natywne, powiedzmy w Gtk i jednocześnie w tle apliakcji pracuje sobie
Twój web server to właśnie dostałeś w prezencie wątki których wcale byc
nie musi.
Post by Maciej Sobczak[*] I bez ograniczania się tylko do tego zastosowania (chociaż GUI było motywacją).
HTTP może służyć również do innych rzeczy, niż GUI. I dlatego też to się nazywa "Embedded HTTP Server" a nie "GUI Framework".
Możliwe że się nie rozumiemy w kwestii GUI. Ja mam na myśli GUI w
programie w którym ktoś wembedował również Twój HTTP. Dzięki temu
aplikacja GUIowa, mimo że z wątkami ma 0 wspolnego, kiedy komunikuje się
z Twoim kodem, musi zarządzać hazardami. W przypadku coroutines/events
nie musi, a jesli chce mieć wątki to ich świadomie używa a jeśli nie
chce to ma ładne event based, pasujace do reszty interfejsy. I co gorsza
takich gotowców jest od cholery a dyski i pamięc tania ...