Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: hazardrok 18. 01. 2021, 18:33:07
-
Ahoj, chtel bych se trochu seznamit s programovanim vicevlaknovych programu v C na linuxu. Mam totiz napsany vlastni jednovlaknovy server a domnivam se, ze pokud mi client zacne delat nejakou slozitou operaci napr. pracovat s databazi (pouzivam SQLite v kombinaci s json-c), tak mi to blokuje dalsi klienty. Abych do stavajiciho jiz odladeneho programu co nejmene zasahoval, vymyslel jsem si tento postup...pokud bude chtit client pristupovat do databaze, tak se tento pozadavek otevre v novem vlakne a jakakoliv dalsi operace totoho clienta bude blokovana dokud vlakno neskonci.
Zjednodusene jsem se to pokusil napsat do kodu, tak jak bych to chtel realizovat a ten zde predkladam. Muj dotaz tedy zni, jestli takto napsany kod bude korektne fungovat a pokud ne, tak jak by to melo vypadat? Ani me nezajima jestli je to takto vhodne resit apod., jde mi jen o princip. Dik za radu.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static int init_function(void *arg);
static void *handle_function(void *arg);
static pthread_t thread_var = -1;
int main(int argc, char *argv[]){
int ret;
//printf("%ld, %ld\n", thread_var, (long)&thread_var);
while(1){
ret = init_function((void *)&thread_var);
if(ret == 1){
printf("vytvoreno nove vlakno\n");
}
//else if(ret == -1){
// printf("vlakno se nepovedlo vytvorit\n");
// }
//else if(ret == -2){
// printf("vlakno stale bezi\n");
// }
//printf("%ld, %ld\n", thread_var, (long)&thread_var);
}
return 0;
}
static int init_function(void *arg){
pthread_t *p_thread = (pthread_t*)arg;
if(*p_thread != -1){
return -2;
}
if(pthread_create(&thread_var, NULL, handle_function, arg)){
return -1;
}
//printf("%ld, %ld\n", thread_var, (long)&thread_var);
pthread_detach(thread_var);
return 1;
}
static void *handle_function(void *arg){
pthread_t *p_thread = (pthread_t*)arg;
//printf("%ld, %ld\n", *p_thread, (long)p_thread);
sleep(5);
printf("konec vlakna\n");
*p_thread = -1;
return NULL;
}
-
Jednoznačne by som sa v takom prípade pozeral smerom https://github.com/libuv/libuv (https://github.com/libuv/libuv). Môžeš síce použiť pthreads a všetko robiť ručne, ale ak nemáš vyslovene dôvod prečo to tak robiť, určite by som skúsil to libuv, minimálne si prečítať čo to dokáže všetko.
-
Vlakna tak funguju, ale musis si dat pozor na synchronizaciu. Pri kompletne oddelenych resourcoch to bude fungovat dobre, ale ked nieco zdielas alebo volas z viac vlaken tu istu kniznicu, tak to musis zamykat, ked nie je dokumentovany opak.
Urcite musis zamykat low level volania ako write(); inak sa vystupy mozu prekryvat. V knizniciach byvaju zamky, ale nie je to pravidlo.
-
O tom zamykani jsem uz neco malo cetl, ale podle me v tomto pripade neni nutne. System je postaven tak, ze kazdy client je jednoznacne pojmenovany a ma ke svemu jmenu prirazenou jednoznacnou databazi. Nemuze do ni tedy vstoput nikdo jiny, protoze system neumoznuje dva stejne pojmenovane clienty zaroven. Zatim to tedy asi pouziju tak, jak jsem si usmyslel dokud se mi to nekde nezhrouti. Mozna misto
static pthread_t thread_var
pouziju neco jako atomic_long thread_var
Pokud spravne chapu princip atomickych promenych, tak by ten program mohl maximalne nefungovat.
-
To ze mas pro kazdeho klienta vlastni databazovy soubor jeste neznamena, ze ta knihovna nema treba nejaky spolecny buffer.
-
No vždycky je dobré něco času věnovat čtení dokumentace, keyword "thread safety", a ideálně i nějaké stack overflow etc. Ony i thread-safe knihovny mívají občas nějaká "ale" - třeba že handler může otevřít kdokoli, ale result musíte číst ze stejného threadu který dělal query. Nebo že některé inicializace safe nejsou a je potřeba je chránit mutexy.
Jinak ta proměnná by měla být pokud se nepletu volatile, jinak Vám do toho (někdy) hodí vidle už optimalizace kompileru, a druhák cokoli složitějšího než správně alignovaný int *) na intelu stejně musíte jet přes nějaké zamykání (jestli jde o rychlé přístupy, tak mutex/futex je dělo na vrabce a stačí spinlocky z rodiny __sync_bool_compare_and_swap() ).
Ale k pthreads - no fungují ale nic lepšího nemáme (ukončování zlobivých threadů je celkem nic moc když se spolehnete jen na to co funguje všude ale to brzo zjistíte sám)
*) Proboha tuhle platform dependent prasárnu neberte jako návod. Ono je to složitější, dost se plete C a C++, taky záleží jestli pro nějakou platformu máte jen starší céčko tak používat nové featury není správná cesta, takže konzervativní je minimalizovat přístup ke sdíleným objektům a tam kde je to nutné, tam ho zamykat.
-
Už mě to nenechá editnout.
Další věc, tenhle postup funguje na holém železe, u userspacu budete mít další problém (který pro teď klidně ignorujte, fungovat to bude, jen je třeba o tom vědět že to není úplně ok). Když si vezmete že jeden thread lockne resource, do toho mu kernel sebere kvantum, tak bude případný další thread viset než ho ten přerušený znova uvolní. Pro to co píšete to je jedno (desetiny sekundy za uherskej rok u příkladu na naučení se). Ale do budoucna je dobré mít pro lock/unlock makra a pak to časem udělat dobře (futexy pro linux, něco přenositelnějšího i jinam)
-
Jinak ta proměnná by měla být pokud se nepletu volatile
Volatile použité na sychronizaci v multithread aplikaci je vždy chyba. Volatile zaručuje jen to, že se vykoná čtení/zápis z paměti a ne z registru, ale z hlediska sychronizace mezi vlákny je to prakticky k ničemu. Není tam žádná memory bariéra, není zaručena atomicita, CPU může udělat read/write reorediring na HW úrovni... Je třeba používat standardní sychronizační primitiva (mutex), které všechno tohle řeší, volatile určitě ne.
-
...sakra ten timeout je malý. Pro Vás je asi nejvhodnější používat na synchronizaci int pthread_mutex_lock(pthread_mutex_t *mutex); a co je obvykle pod tím je tady https://eli.thegreenplace.net/2018/basics-of-futexes/
-
Naozaj treba prejst vsetky kniznice. Zavislosti to cele este komplikuju - treba ked pouzivas kniznicu A a potom kniznicu B, ktora pouziva A, tak je treba rovnakymi zamkami zamykat pouzitia A a B.
V tvojom pripade precitaj https://sqlite.org/threadsafe.html a https://stackoverflow.com/questions/26374323/is-the-json-c-library-thread-safe a pripadne podobne pre vsetky ostatne implementacie, ktore pouzivas.
Volatile nepouzivaj ked nepracujes s HW - garantuje to veci, ktore nutne nechces (premenna sa nedrzi v registroch) a negarantuje to veci, ktore chces - negarantuje to atomicitu zapisu premennej, reordering na urovni HW atd. Ked musis nieco zdielat, tak pouzivaj bud atomic builtins (https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html) alebo memory barriers. Alebo v najlepsom pripade zamky.
U threadov sa tazko hladaju chyby, takze skusit to nestaci. Na niektore bugy pouzi kompilaciu cez Clang s -fsanitize=thread alebo to zbehni cez valgrind --tool=helgrind.
-
Diky za pripominky. Pokusim se to shnout...
1. muj jednoduchy priklad nebyl vylozene vyvracen ani pohanen a lze ho pouzit
2. pokud budou pouzity nejake knihovny, musi byt bud "thread safety" nebo je potreba pouzit nejakou pokrocilejsi techniku spravy vlaken aby se nestalo to, ze vlakna budou prustupovat k jednomu zdroji, ktery si budou navzajem menit napr. vyrovnavaci bufer nebo nejaky statusovy priznak. Zde zminim napr. mutex.
3. pri hledani problemu muze pomoci najeky ladici nastroj napr. valgrind apod.
Overil jsem si, ze knihovna pro SQlite je "thread safety", protoze kod:
ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
vraci:
SQLITE_OK
coz podle dokumentace znamena, ze je mozne pouzit tento mod pracujici s vice vlakny. Tato knihovna se tedy zda byt OK.
U json-c si nejsem vubec jistej, protoze mi asi chybi zkusenosti s pochopenim principu. Tam je ale situace trochu jina, protoze json se pouziva pouze jednou pri uplne prvnim pripojeni klienta o krerem system nema zadne informace. Jakmile si informace vytvori, uz se pro tohoto clienta nikdy nepouzije. Volani funkci teto knihovny tedy neni potreba do jineho vlakna davat.
Zaverem mi tedy vyplyva, ze je pokud se mi to povede odladit a bude to fungovat, tak bych na vetsi problemy (nez uz ted mam) nemel narazit.
-
Mě by zajímalo, co konkrétně čeká autor dotazu že se tady dozví?
- Lze zpracovávat požadavky klientů v samostatném vlákně? Ano, ale vytvářet nové vlákno per request může být drahé.
- Musí si hlídat přístup ke zdrojům v MT aplikaci? Ano.
- Existuje i jiný způsob? Existuje, třeba dělat to asynchronně např. s pomocí libuv.
Jediná možnost, jak se dozvědět zda autorovo konkrétní řešení funguje je napsat testy. Pokud budou testy modelovat veškeré podporované scénáře a budou fungovat, tak je to řešení asi funkční. No a pokud už budou testy, tak není problém použít třeba thread sanitizer a další nástroje na detekci chyb.
-
Jsem presvedecn, ze dotaz znel v podstate jasne...Ptal jsem se na to jestli ten muj prilozenej kod bude fungovat korektne. A cekal jsem ze dostanu odpoved. Take jsem presvedecn, ze jsem jednoznacnou odpoved nedostal, ale urcite ted vim neco vice o konfiguraci SQLite. Rada, ze existuje jiny zpusob napr. libuv neni odpoved na moji otazku. Tim se samozrejme nechci nikoho kdo prispival dotknout, na druhou stranu by me zajimalo kam uzivatel anonacct miri?
-
Ptal jsem se na to jestli ten muj prilozenej kod bude fungovat korektne.
Nebude fungovat korektně, máš tam data race a helgrind ti to řekne. K proměnné thread_var přistupuješ z více vláken bez synchronizace.
g++ -lpthread -o test -g main.cc
valgrind --tool=helgrind ./test
==5579== Possible data race during read of size 8 at 0x10C048 by thread #1
==5579== Locks held: none
==5579== at 0x1091AF: init_function(void*) (main.cc:37)
==5579== by 0x10917F: main (main.cc:17)
==5579==
==5579== This conflicts with a previous write of size 8 by thread #2
==5579== Locks held: none
==5579== at 0x109232: handle_function(void*) (main.cc:58)
==5579== by 0x483C8B6: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so)
==5579== by 0x4886FA2: start_thread (pthread_create.c:486)
==5579== by 0x4CBA4CE: clone (clone.S:95)
==5579== Address 0x10c048 is 0 bytes inside data symbol "_ZL10thread_var"
-
no super...snad se konecne pohnu kupredu (rad bych pouzil spravnym smerem, ale do toho je jeste daleko :))
Pridal jsem do kodu mutex a zkusil jak se to bude chovat. Po spusteni pres:
valgrind --tool=helgrind ./main
jsem dostal po skonceni programu tuto hlasku
==3853== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 50221857 from 38)
Vyslednu kod je zde:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
static int init_function(void);
static void *handle_function(void *arg);
static uint8_t thread_var = 0x00;
static pthread_t thread;
static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
int main(int argc, char *argv[]){
int ret;
int c_run = 100;
while(1){
ret = init_function();
if(ret == 1){
//printf("vytvoreno nove vlakno\n");
if(c_run != 0){ c_run--;}
else{ break;}
}
}
return 0;
}
static int init_function(void){
uint8_t var;
pthread_mutex_lock(&mymutex);
var = thread_var;
if(var == 0x00){ thread_var = 0xFF;}
pthread_mutex_unlock(&mymutex);
if(var == 0xFF){
return -2;
}
if(pthread_create(&thread, NULL, handle_function, NULL)){
//vlakno nebylo vytvoreno, musim shodit thread_var
pthread_mutex_lock(&mymutex);
thread_var = 0x00;
pthread_mutex_unlock(&mymutex);
return -1;
}
pthread_detach(thread);
return 1;
}
static void *handle_function(void *arg){
sleep(1);
pthread_mutex_lock(&mymutex);
thread_var = 0x00;
pthread_mutex_unlock(&mymutex);
return NULL;
}
Ze zacatku mi to nefungovalo. Po chvili mi doslo, ze problem bude asi v puvodnim volani funkce printf na konci vlakna. Kdyz jsem ji odstranil uz to zadne chyby nehlasilo. Uz mi jsou ty dotazy skoro trapny, ale je toto jiz korektni?
-
Mimo puvodni dotaz.
Multithreading v C je pain a porad jednou nohou v pruseru. Business kod taky pain, prenositelnost a devops peklo.
A to nejenom pri vyvoji ale hlavne dale pri zmenovkach a udrzbe.
Neznam samozrejme pozadi tohoto programu, ale zvazil bych pouziti vhodnejsiho jazyka.
Treba v GO je to pres gorutiny s prstem v nose, mechanismus channelu je z bezpecny a blbuvzdorny
Nebo v Jave pri pouziti netty.io
-
Mimo puvodni dotaz.
Multithreading v C je pain a porad jednou nohou v pruseru. Business kod taky pain, prenositelnost a devops peklo.
A to nejenom pri vyvoji ale hlavne dale pri zmenovkach a udrzbe.
Neznam samozrejme pozadi tohoto programu, ale zvazil bych pouziti vhodnejsiho jazyka.
Treba v GO je to pres gorutiny s prstem v nose, mechanismus channelu je z bezpecny a blbuvzdorny
Nebo v Jave pri pouziti netty.io
Pthreads jsou “pain”, v C je vždy lepší použít Grand Central Dispatch (což je pro BSD, Linux i Windows). V C++ pak existují další vhodné knihovny.
-
Treba v GO je to pres gorutiny s prstem v nose, mechanismus channelu je z bezpecny a blbuvzdorny
S tou bezpečností ani blbuvzdornstí bych to nepřeháněl. Stačí si přes channel nevhodně poslat pointer a je na světě problém úplně stejnej jako v C. A vzhledem k tomu, že pointery na structy jsou tak nějak default... Zákeřnější varianta stejné chyby je poslat si sice kopii structu, ale nevšimnout si, že má přes pointer embeddovaný jiný struct. Moc pěkná chyba, hledat ji je čirá extáze :)
Opravdu blbuvzdornou konkurentnost má Erlang, kde chybu tohodle typu udělat z principu nejde, protože sdílet paměť mezi vlákny ("procesy") prostě nejde a basta :) I tam samozřejmě pořád zůstává možnost deadlocku.
-
Stačí si přes channel nevhodně poslat pointer a je na světě problém úplně stejnej jako v C.
Jak "nevhodně"? Když vytvořím objekt a pak ukazatel na něj pošlu kanálem, tak příjemce s ním může normálně pracovat a GC ho nechá na pokoji, dokud na něj existují odkazy (když je v bufferu, tak do uzavření kanálu).
-
Jak "nevhodně"? Když vytvořím objekt a pak ukazatel na něj pošlu kanálem, tak příjemce s ním může normálně pracovat a GC ho nechá na pokoji, dokud na něj existují odkazy (když je v bufferu, tak do uzavření kanálu).
No právě. Vytvořím tak shared memory úplně stejně jako v C, se všema nebezpečíma, který to v C má. Žádná větší "bezpečnost" se v takovým případě neděje. Čili "blbuvzdorný" to moc není, dají se tam velice snadno udělat stejný průsery jako v C.
-
Jak "nevhodně"? Když vytvořím objekt a pak ukazatel na něj pošlu kanálem, tak příjemce s ním může normálně pracovat a GC ho nechá na pokoji, dokud na něj existují odkazy (když je v bufferu, tak do uzavření kanálu).
No právě. Vytvořím tak shared memory úplně stejně jako v C, se všema nebezpečíma, který to v C má. Žádná větší "bezpečnost" se v takovým případě neděje. Čili "blbuvzdorný" to moc není, dají se tam velice snadno udělat stejný průsery jako v C.
A co když ten odkazovaný objekt je immutable?
-
A co když ten odkazovaný objekt je immutable?
Pokud je immutable, tak samozřejmě k žádnému problému nedojde. Čili úplně stejně jako v C :) S tím rozdílem, že Go neumí konstanty hlídat tak dobře jako C :) (např. const field structu)
-
Takova mensi ilustrace:
https://play.golang.org/p/jjbq2b4NyI0
Kdyz si predstavim, ze obsah A a B je nedokumentovany a ja pisu jenom consumer(), asi budu hodne kroutit hlavou, co delam spatne...
-
Takova mensi ilustrace:
https://play.golang.org/p/jjbq2b4NyI0
Kdyz si predstavim, ze obsah A a B je nedokumentovany a ja pisu jenom consumer(), asi budu hodne kroutit hlavou, co delam spatne...
A proto, milé děti, nepraste a sdílejte jen immutable objekty.
-
A proto, milé děti, nepraste a sdílejte jen immutable objekty.
To je sice dobra rada a radostne bych souhlasil, jenze imutabilita nejde v Go vynutit a dokonce ani zkontrolovat.
Takze v Go proste zadny dobry reseni nemas. Imutabilitu nevynutis, ze struct neobsahuje (na jakekoliv urovni!) zadny pointer nezkontrolujes a jediny, co ti zustane, jsou neopodstatnena velkolepa prohlaseni, ze kanaly jsou "bezpecne a blbuvzdorne", pricemz nejsou ani jedno, protoze narozdil od Erlangu v gocku implementovali CSP ponekud nedomrle. O cemz se ale nesmi mluvit, protoze Go je dokonale ve sve jednoduchosti ;)
-
A proto, milé děti, nepraste a sdílejte jen immutable objekty.
To je sice dobra rada a radostne bych souhlasil, jenze imutabilita nejde v Go vynutit a dokonce ani zkontrolovat.
Takze v Go proste zadny dobry reseni nemas. Imutabilitu nevynutis, ze struct neobsahuje (na jakekoliv urovni!) zadny pointer nezkontrolujes a jediny, co ti zustane, jsou neopodstatnena velkolepa prohlaseni, ze kanaly jsou "bezpecne a blbuvzdorne", pricemz nejsou ani jedno, protoze narozdil od Erlangu v gocku implementovali CSP ponekud nedomrle. O cemz se ale nesmi mluvit, protoze Go je dokonale ve sve jednoduchosti ;)
Tolik k alternativní realitě. Skutečnost je, že se to všeobecně ví a ty si jen s velkým kraválem myslíš, žes objevil Ameriku ;)
-
A proto, milé děti, nepraste a sdílejte jen immutable objekty.
jenze imutabilita nejde v Go [...] zkontrolovat.
Takze v Go proste zadny dobry reseni nemas. [...] ze struct neobsahuje (na jakekoliv urovni!) zadny pointer nezkontrolujes
Nic z toho není pravda, kontrolovat kompozici objektů jde a dokonce se to v částech standardní knihovny využívá. Donovan a Kernighan mají v knize “The Go programming language” příklady.
-
Nic z toho není pravda, kontrolovat kompozici objektů jde a dokonce se to v částech standardní knihovny využívá. Donovan a Kernighan mají v knize “The Go programming language” příklady.
Nevím, co si představuješ pod "kontrolovat kompozici objektů". Jestli to nějaký řešení má, tak mi ho ukaž na tom příkladu.
1. Píšu jenom consumer(), producer() a main()
2. Neznám obsah B, není dokumentovaný
3. Chci, aby na mě překladač zařval, že dělám nebezpečnou věc - buď že měním něco, co měnit nemám, nebo že používám něco, co se mi pod rukama může změnit. Oboje v C udělat jde.
-
Nevím, co si představuješ pod "kontrolovat kompozici objektů".
Chci, aby na mě překladač zařval,
To, cos napsal, zjistit, jestli někde v hloubi objektového grafu není ukazatel.
Akorát už měníš “zadání”, nejdřív píšeš “není možné”, a pak “chci, aby překladač zařval”. To není totéž. Nejdříve si přečti *pozorně* tu knihu. Pak se nauč vyjadřovat přesně. No a pak si můžeme zase popovídat ;)
P.S. A ano, bylo by mnohem lepší, kdyby Go (a vůbec všechny jazyky s kompozitními typy) mělo u polí modifikátor “initonly”, ubylo by blábolů prvotních i blábolů reagujících na bláboly :)
-
Nevím, co si představuješ pod "kontrolovat kompozici objektů".
Chci, aby na mě překladač zařval,
To, cos napsal, zjistit, jestli někde v hloubi objektového grafu není ukazatel.
Akorát už měníš “zadání”, nejdřív píšeš “není možné”, a pak “chci, aby překladač zařval”. To není totéž. Nejdříve si přečti *pozorně* tu knihu. Pak se nauč vyjadřovat přesně. No a pak si můžeme zase popovídat ;)
P.S. A ano, bylo by mnohem lepší, kdyby Go (a vůbec všechny jazyky s kompozitními typy) mělo u polí modifikátor “initonly”, ubylo by blábolů prvotních i blábolů reagujících na bláboly :)
Nenašel by se nějaký příklad, co není za paywallem?
-
Nevím, co si představuješ pod "kontrolovat kompozici objektů".
Chci, aby na mě překladač zařval,
To, cos napsal, zjistit, jestli někde v hloubi objektového grafu není ukazatel.
Akorát už měníš “zadání”, nejdřív píšeš “není možné”, a pak “chci, aby překladač zařval”. To není totéž. Nejdříve si přečti *pozorně* tu knihu. Pak se nauč vyjadřovat přesně. No a pak si můžeme zase popovídat ;)
P.S. A ano, bylo by mnohem lepší, kdyby Go (a vůbec všechny jazyky s kompozitními typy) mělo u polí modifikátor “initonly”, ubylo by blábolů prvotních i blábolů reagujících na bláboly :)
Nenašel by se nějaký příklad, co není za paywallem?
Z hlavy nevím, ale můžu zkusit něco najít o “obvyklých podezřelých” (například Cheney apod.). Stay tuned ;)
-
To, cos napsal, zjistit, jestli někde v hloubi objektového grafu není ukazatel.
Coz prave PRAKTICKY nejde. Pouzivam nejakou knihovnu. Tahle informace neni soucasti API, cili i kdyz si projdu zdrojaky, je mi to platny jak mrtvymu zimnik, protoze uz s nasledujici zmenou MINOR verze se to muze zmenit.
A vubec nemusi jit o cizi knihovnu. Muze jit o dve casti jedne aplikace, ktere pisou dva tymy. Jeden vubec nevi, ze druhy spoliha na to, ze tam ukazatel neni.
A ani o dva tymy nemusi jit. Muzu to klidne psat sam a po trech letech uz si vubec nepamatuju, ze jsem na to, ze v B zadny ukazatel neni, spolihal. Bezelstne ho tam pridam a najednou mi to zacne na produkci delat psi kusy, neznamo proc a jenom obcas.
Akorát už měníš “zadání”, nejdřív píšeš “není možné”, a pak “chci, aby překladač zařval”. To není totéž.
To JE totez. Pokud prekladac nezarve, tak to neni ROZUMNE, PRAKTICKY mozne. Protoze pokud ta informace neni ve zdrojaku (a opakuju: C to umi ve zdrojaku vyjadrit) a prekladac ji neumi zkontrolovat, muzu o tom, ze to jde, tak leda pindat na rootu a v praxi to porad bude u zakaznika zahadne padat. Coz neni moje definice "bezpecneho" reseni konkurentnosti.
-
Z hlavy nevím, ale můžu zkusit něco najít o “obvyklých podezřelých” (například Cheney apod.). Stay tuned ;)
Jezkovanoho, nedelej z toho vedu. Ukazal jsem problematicky priklad na par radku. Pokud jde nejak opravit, tak to bude oprava na par radku. Tak shut up and show the code :)
-
Ať už k tomu zdroják máš nebo ne, místo (abych použil tvou terminologii) pindání si to kontroluj za běhu (třeba asercí), pak ti to bude fungovat i s knihovnami nebo pluginy třetích stran a pokud rozumně testuješ, k zákazníkovi se taková chyba nedostane.
BTW ta kniha je fakt dobrá, protože se nezaměřuje úzce jen na technické věci, ale právě i na testování a jiné užitečné postupy. Prozřel bys. Možná. Doufám. :P
-
Z hlavy nevím, ale můžu zkusit něco najít o “obvyklých podezřelých” (například Cheney apod.). Stay tuned ;)
Jezkovanoho, nedelej z toho vedu. Ukazal jsem problematicky priklad na par radku. Pokud jde nejak opravit, tak to bude oprava na par radku. Tak shut up and show the code :)
Tohle nebylo na tebe.
-
Ať už k tomu zdroják máš nebo ne, místo (abych použil tvou terminologii) pindání si to kontroluj za běhu (třeba asercí), pak ti to bude fungovat i s knihovnami nebo pluginy třetích stran a pokud rozumně testuješ, k zákazníkovi se taková chyba nedostane.
Tvl, to je jak kdyz mluvim se svyma deckama: ja jsem chtela... za chvilku... mozna... kdyby... jo, nekdy...
Tak nam to elegantni reseni ukaz, ne? Myslim, ze kdyz ty dva radky kodu uvidime, prozreme daleko spis, nez kdyz budes trousit odkazy na knizky, ktery nemame k dispozici.
Tohle nebylo na tebe.
Ja vim.
-
Treba v GO je to pres gorutiny s prstem v nose, mechanismus channelu je z bezpecny a blbuvzdorny
S tou bezpečností ani blbuvzdornstí bych to nepřeháněl. Stačí si přes channel nevhodně poslat pointer a je na světě problém úplně stejnej jako v C. A vzhledem k tomu, že pointery na structy jsou tak nějak default... Zákeřnější varianta stejné chyby je poslat si sice kopii structu, ale nevšimnout si, že má přes pointer embeddovaný jiný struct. Moc pěkná chyba, hledat ji je čirá extáze :)
Opravdu blbuvzdornou konkurentnost má Erlang, kde chybu tohodle typu udělat z principu nejde, protože sdílet paměť mezi vlákny ("procesy") prostě nejde a basta :) I tam samozřejmě pořád zůstává možnost deadlocku.
No to je sice pravda, lec musim s tim pointerem aktivne prasit dale v main threadu.
Pokud pouzivam aspon trochu stabni kulturu, poslu pointer do IN channelu a v main threadu zapominanm na jeho existenci, tam se to bezpecne posle do jedne instance gorutiny (tudiz nenastane situace, ze 2 gorutiny delaji na stejnem pointeru) a vysledny pointer na vysledny gorutinou modifikovany struct nacpu do OUT channelu, odkud si to v main threadu zase vytahnu.
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
-
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
A to prave nestaci. Protoze v te strukture, kterou posilas, muze byt nejaky pointer z te odesilajici goroutiny, a ty o tom vubec nevis (nejaka funkce si tam ulozila neco, cos necekal, ze si tam ulozi).
Jak rika Idris, musel bys kontrolovat cely strom - ne jenom tu horni strukturu, ale i vsechny ji odkazovane struktury.
-
Treba v GO je to pres gorutiny s prstem v nose, mechanismus channelu je z bezpecny a blbuvzdorny
S tou bezpečností ani blbuvzdornstí bych to nepřeháněl. Stačí si přes channel nevhodně poslat pointer a je na světě problém úplně stejnej jako v C. A vzhledem k tomu, že pointery na structy jsou tak nějak default... Zákeřnější varianta stejné chyby je poslat si sice kopii structu, ale nevšimnout si, že má přes pointer embeddovaný jiný struct. Moc pěkná chyba, hledat ji je čirá extáze :)
Opravdu blbuvzdornou konkurentnost má Erlang, kde chybu tohodle typu udělat z principu nejde, protože sdílet paměť mezi vlákny ("procesy") prostě nejde a basta :) I tam samozřejmě pořád zůstává možnost deadlocku.
No to je sice pravda, lec musim s tim pointerem aktivne prasit dale v main threadu.
Pokud pouzivam aspon trochu stabni kulturu, poslu pointer do IN channelu a v main threadu zapominanm na jeho existenci, tam se to bezpecne posle do jedne instance gorutiny (tudiz nenastane situace, ze 2 gorutiny delaji na stejnem pointeru) a vysledny pointer na vysledny gorutinou modifikovany struct nacpu do OUT channelu, odkud si to v main threadu zase vytahnu.
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
Tak jest. Taky v tom nevidím nějaký zásadní problém. Ani nejde IMHO o štábní kulturu, stačí používat mozek.
Na druhou stranu, i přes Prýmkovu hysterii jde o hezký podnět k zamyšlení.
-
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
A to prave nestaci. Protoze v te strukture, kterou posilas, muze byt nejaky pointer z te odesilajici goroutiny, a ty o tom vubec nevis (nejaka funkce si tam ulozila neco, cos necekal, ze si tam ulozi).
Jak rika Idris, musel bys kontrolovat cely strom - ne jenom tu horni strukturu, ale i vsechny ji odkazovane struktury.
Tak ale co ti brání? Si to třeba v jednotkových testech zkontroluj, vždyť to není problém.
-
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
A to prave nestaci. Protoze v te strukture, kterou posilas, muze byt nejaky pointer z te odesilajici goroutiny, a ty o tom vubec nevis (nejaka funkce si tam ulozila neco, cos necekal, ze si tam ulozi).
Jak rika Idris, musel bys kontrolovat cely strom - ne jenom tu horni strukturu, ale i vsechny ji odkazovane struktury.
Tomu rozumim, psal jsem o rozumne blbvzdornosti hlavne v porovnani s C.
Mechanismus pointeru a channelu neni slozity na pochopeni.
V normalnim programu mi ty pointerovane data budou vznikat lokalne v ramci loop smycky (a nasledne hned zapominany), poslany do IN channelu a vysledek vycitan z OUT channelu.
Samozrejme nemuzu posilat pointery na volatilni data.
V Jave to same, kdyz poslu ArrayList, do jehoz polozek mi nekdo z boku hrabe, dopadne to blbe.
V Jave sice muzes tomuto zamezit (https://dev.to/monknomo/make-an-immutable-object---in-java-480n), ale kdo to v realu dela.
Pokud opravdu nastane situace, ze mi nekdo modikuje predavaci datovou strukturu, je neco hodne blbe v samotnem navrhu programu. Ale samozrejme je pravda, ze moznost definice immutable jednoduchou syntaxi je velice prinosna featura.
Pokud budu chtit v danem pripade zamezit tomuto v GO, staci do channelu posilat pointery na hluboke kopie danych struktur a hned je v main threadu zapominat.
-
Tak jest. Taky v tom nevidím nějaký zásadní problém. Ani nejde IMHO o štábní kulturu, stačí používat mozek.
Na druhou stranu, i přes Prýmkovu hysterii jde o hezký podnět k zamyšlení.
Jakou hysterii?! Ja jenom konstatuju, co si myslim a svoje tvrzeni dokladam konkretnim prikladem. Nevylucuju, ze se mylim, ten priklad jde nejak elegantne opravit a tim mou tezi zpochybnit. Ale zatim to jaksi nikdo neudelal. A pritom staci pouzit mozek a napsat par radek kodu misto desitek radek prispevku, ze :)
Tak ale co ti brání? Si to třeba v jednotkových testech zkontroluj, vždyť to není problém.
Brani mi v tom to, ze to neumim udelat tak, aby to bylo spolehlive (jeste porad se bavime o "bezpecnosti", nebo uz ne?)
A to je presne ten duvod, proc chci od tebe priklad. Protoze jenom na ten ti pripadne muzu dat protipriklad. Tvrzeni "staci pouzivat mozek" vyvratit neumim, cili je pro me dost bezcenne...
-
Takze staci nebyt uplny dobytek a prace v GO je rozumne bezpecna.
A to prave nestaci. Protoze v te strukture, kterou posilas, muze byt nejaky pointer z te odesilajici goroutiny, a ty o tom vubec nevis (nejaka funkce si tam ulozila neco, cos necekal, ze si tam ulozi).
Jak rika Idris, musel bys kontrolovat cely strom - ne jenom tu horni strukturu, ale i vsechny ji odkazovane struktury.
Pokud budu chtit v danem pripade zamezit tomuto v GO, staci do channelu posilat pointery na hluboke kopie danych struktur a hned je v main threadu zapominat.
K tomu bych dodal: CoW. A je po problému.
-
Standa B. právě navrhnul ještě lepší řešení než kontrolu. Problem solved.
-
Krom toho, nejsem si uplne jisty, ze to je reseni pro vsechny situace. Musim zapremyslet :)
Minimalne samozrejme nefunguje pro ruzny resourcy typu sitovy spojeni, filedescriptor apod., ale to asi neni potreba zduraznovat.
Spis premyslim, jestli by tam nebyly nejaky jiny speky :)
-
[sorry, omylem jsem si misto citace zmenil prispevek. Tenhle mel byt pred tim pred nim]
Mechanismus pointeru a channelu neni slozity na pochopeni.
O tom tady asi neni sporu.
V normalnim programu mi ty pointerovane data budou vznikat lokalne v ramci loop smycky
Tuhle predstavu "normalniho programu" asi uplne nesdilim. Struktury podle me bezne obsahuji kde co, co vzniklo kde jak.
Samozrejme, pokud za "normalni program" budes povazovat jenom nejaky producer-consumer, co si posila inty, tak pak jo :)
Pokud budu chtit v danem pripade zamezit tomuto v GO, staci do channelu posilat pointery na hluboke kopie danych struktur a hned je v main threadu zapominat.
Abych te citoval: "ale kdo to v realu dela" :)
Krom toho, nejsem si uplne jisty, ze to je reseni pro vsechny situace. Musim zapremyslet :)
K tomu bych dodal: CoW. A je po problému.
No ty ses king teda. Takze problem "v Go nejde zarucene bezpecne pouzivat channely" jsi prevedl na problem "v Go nejde zarucene bezpecne implementovat CoW" :)
-
Minimalne samozrejme nefunguje pro ruzny resourcy typu sitovy spojeni, filedescriptor apod., ale to asi neni potreba zduraznovat.
Kdo by proboha kanálem posílal síťová spojení nebo handle na soubor? Někdo po lobotomii? :)
A když už to pošle, tak to nebude měnit, že...
-
K tomu bych dodal: CoW. A je po problému.
"v Go nejde zarucene bezpecne pouzivat channely" jsi prevedl na problem "v Go nejde zarucene bezpecne implementovat CoW" :)
Obávám se, žes něčemu neporozuměl. Jen teď nevím, jestli jde o CoW, nebo něco složitějšího. Fakt v tom hledáš něco, co v tom není (nebo jen schválně prudíš), protože už tu padly dva funkční návrhy, jak to řešit.
-
Kdo by proboha kanálem posílal síťová spojení nebo handle na soubor? Někdo po lobotomii? :)
A když už to pošle, tak to nebude měnit, že...
Ja ti nevim, Idrisi, ty ses prece dost chytrej. To mi vazne nerozumis, o cem mluvim?
Mam nejakou svoji strukturu a v ni mam nejakou strukturu, kterou jsem ziskal z nejake knihovny. A ted NEVIM, jestli ji muzu bezpecne poslat kanalem ze sve goroutiny A do sve goroutiny B. Ne, ja s ni nechci dal pracovat v goroutine A. Je jenom NEVIM, jestli ta struktura nahodou ssebou netahne neco, co by mohlo po tehle operaci zpusobit problem. Uz si rozumime? Problem je v tom ze v Go nevim, co je bezpecne a co neni. A prekladac mi to neumi rict. Uz si rozumime?
Napriklad kdyby ta struktura obsahovala mutex, tak je problem. Takze kazdej, kdo vlozi do nejake struktury mutex, musi byt po lobotomii?!
-
Obávám se, žes něčemu neporozuměl. Jen teď nevím, jestli jde o CoW, nebo něco složitějšího. Fakt v tom hledáš něco, co v tom není (nebo jen schválně prudíš), protože už tu padly dva funkční návrhy, jak to řešit.
Pokud chces bezpecne implementovat CoW, musis mit k dispozici dobre fungujici const. Coz Go nema.
-
Napriklad kdyby ta struktura obsahovala mutex, tak je problem.
Vymýšlíš nesmysly. To problém není, dokud na ten mutex nesáhneš.
Evidentně se tu všichni shodneme, že když někdo hodně prasí, tak můžou v programech s více vlákny nastat probémy. Nejen v Go. To bych nevyčítal žádnému jazyku, ale samozřejmě, kdo chce psa bít...
-
Obávám se, žes něčemu neporozuměl. Jen teď nevím, jestli jde o CoW, nebo něco složitějšího. Fakt v tom hledáš něco, co v tom není (nebo jen schválně prudíš), protože už tu padly dva funkční návrhy, jak to řešit.
Pokud chces bezpecne implementovat CoW, musis mit k dispozici dobre fungujici const. Coz Go nema.
Prosím omezit produkci pochybných tvrzení na jedno za den, jinak se nám tu budou akumulovat.
-
Vymýšlíš nesmysly. To problém není, dokud na ten mutex nesáhneš.
Evidentně se tu všichni shodneme, že když někdo hodně prasí, tak můžou v programech s více vlákny nastat probémy. Nejen v Go. To bych nevyčítal žádnému jazyku, ale samozřejmě, kdo chce psa bít...
Ale to neni muj mutex! To je mutex, ktery si do te struktury dala ta knihovna. Ja vubec nevim, ze tam je, natoz abych na nej chtel sahat. Ja proste NEVIM, chapes?!
-
Prosím omezit produkci pochybných tvrzení na jedno za den, jinak se nám tu budou akumulovat.
Kdyz dovolis, omezim celkovy pocet prispevku na nulu, protoze tohle je vazne nedustojny.
-
Vymýšlíš nesmysly. To problém není, dokud na ten mutex nesáhneš.
Evidentně se tu všichni shodneme, že když někdo hodně prasí, tak můžou v programech s více vlákny nastat probémy. Nejen v Go. To bych nevyčítal žádnému jazyku, ale samozřejmě, kdo chce psa bít...
Ale to neni muj mutex! To je mutex, ktery si do te struktury dala ta knihovna. Ja vubec nevim, ze tam je, natoz abych na nej chtel sahat. Ja proste NEVIM, chapes?!
Když o něm nevíš, není problém. OMG ::)
-
Prosím omezit produkci pochybných tvrzení na jedno za den, jinak se nám tu budou akumulovat.
Kdyz dovolis, omezim celkovy pocet prispevku na nulu, protoze tohle je vazne nedustojny.
To bude nejlepší, protože CoW a const v jazyce nijak nesouvisí.
-
To bude nejlepší, protože CoW a const v jazyce nijak nesouvisí.
Z toho tvrzeni jsi vypustil to "bezpecna implementace".
-
Rozjela se tady docela flamewar. Moc teda nechápu proč, go skutečně negarantuje, že v programu není data race. Pokud chci takové garance, musím sáhnout jinam (https://medium.com/@deckarep/paradigms-of-rust-for-the-go-developer-210f67cd6a29).
-
Rozjela se tady docela flamewar. Moc teda nechápu proč, go skutečně negarantuje, že v programu není data race. Pokud chci takové garance, musím sáhnout jinam (https://medium.com/@deckarep/paradigms-of-rust-for-the-go-developer-210f67cd6a29).
Skvělý odkaz, merci beaucoup.
-
Skvělý odkaz, merci beaucoup.
Docela pěkný, ale takový základní věci, nic extra, ne?
Jestli si radši čteš než diskutuješ a prověřuješ argumenty, tak třeba líp než to moje plkání přijmeš:
https://medium.com/@sargun/go-concurrency-considered-harmful-26499a422830 (vypichuju odstavec "The worst part about this is that there is no guarantee ...")
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/#mutability-is-hardcoded-in-the-language
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/#mutability-and-channels-race-conditions-made-easy
-
Mimochodem, v tom druhém odkazu je zásadní protiargument proti tomu navrženému řešení s (manuálním) deep copy:
private fields can't be accessed with reflection
Na to jsem si nevzpomněl. Showstopper.
-
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku (https://www.linux.cz/noviny/1998-0809/clanek11.html). Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál. Hrál jsem si s tou synchronizací v C a základním C++ postupně víc a víc, až jsem v jednom proprietárním prográmku měl asi 7 různých tříd objektů (které cosi obalovaly), každý měl svá 1-4 vlákna, mezi sebou si předávaly "práci" a pochopitelně se přitom všelijak zamykaly... jako houfec baletek. Fronta nebo obecně nějaká hromádka krmení, ochráněná podmínkovou proměnnou, je mocná zbraň :-) Není vůbec na škodu, myslet trochu "mimo předdefinované škatulky", a ze shůry daných základních synchronizačních primitiv si stavět složitější konstrukce na míru svému problému. Třeba více producentů pro jednoho konzumenta... podmínkovou proměnnou lze chránit prostou frontu, nebo třeba nějaký složitý key-value index s multikriteriální porovnávací funkcí... Jednalo se tehdy o nějakou komunikační gateway mezi více rozhraními, a dalo se to celé rozdrobit na datové objekty držené v indexech, které na sebe navzájem odkazovaly, kolem každého objektu tančilo několik vláken... jedním ze základních návrhových principů bylo, že každé vlákno smí delší dobu (až na neurčito) blokovat právě v jednom bodě, aby se zabránilo nepříjemnostem typu zbytečné vzájemné čekání nebo dokonce uváznutí. Tím jediným bodem mohla být podmínková proměnná (vlákno = konzument) nebo třeba čekání na vstup (událost) od fyzického I/O zařízení... Všimněte si, že při čekání na podmínkové proměnné je související mutex *odemčený*. Držet mutex dlouhodobě zamčený je hřích - přípustný pouze v případě, že to fakt nejde udělat rychleji nebo odložit na dobu, kdy zámek není potřeba (třeba když je zámkem chráněna manipulace s nějakým btree asociativním polem / indexem, byť u rozsáhlejšího btree může být třeba rebalancing procesorově a časově náročný).
BTW Když si vezmete že jeden thread lockne resource, do toho mu kernel sebere kvantum, tak bude případný další thread viset než ho ten přerušený znova uvolní. Pro to co píšete to je jedno (desetiny sekundy za uherskej rok u příkladu na naučení se). Ale do budoucna je dobré mít pro lock/unlock makra a pak to časem udělat dobře (futexy pro linux, něco přenositelnějšího i jinam)
Možná tomu špatně rozumím, ale zrovna v tomhle případě mě držený zámek neuráží :-) Pokud má konkrétní vlákno zrovna práci na nějakém zamčeném "vzácném zdroji", třeba se delší dobu hrabe v nějakém indexu, a přeruší ho preemptivně scheduler, tak to vlákno prostě zůstane ve stavu "running". A pokud nějaká další vlákna trpělivě čekají na tentýž zámek, tak holt čekají dál a zcela po právu / smysluplně. Z pohledu scheduleru tato další vlákna "z vlastní vůle spí". Takže scheduler půjčí procesor na chvilku nějakému jinému procesu, který by také rád běžel. Halt zas chvilku někdo jiný tahá pilku. Nebo pokud se nikdo jiný o procesor nehlásí, dostane ho obratem zpátky naše původní vlákno, které se chce ještě chvilku hrabat v tom svém indexu - vlákno dostane procesor zpátky, protože je z pohledu scheduleru "running". Prostě: které vlákno má práci, a indikuje toto scheduleru, má šanci procesor dostat zpátky - a vlákna spící na podmínkových proměnných patrně spí dál zcela oprávněně, a při správném rozvržení dat a vláken je to jako celek dost slušně efektivní.
Mám na tuhle dobu a programátorské problémy hezké vzpomínky. Jak shluknout v kódu objekt (struct) a k němu náležející vlákna. Jak nastartovat vlákno a "memberizovat" ho, aby běželo jako metoda konkrétního objektu. Jak do toho objektu (třídy/structu) zakomponovat podmínkovou proměnnou a mutex, které si "vlastní" vlákna objektu budou zdvořile předávat. Jak to zamykání zabalit do "manipulačních" metod, aby další kód volající tyto metody nemusel řešit pthread primitiva. Jak z různých tříd takových "rozvlákněných objektů" skládat hierarchie / mesh topologie, a zároveň zajistit "graceful cleanup" při ukončení jednotlivého vlákna, případně kaskádovitý úklid vláken a objektů při ukončení programu... Nabízí se, zapojit do hry reference counting = osobně jsem přidával do "užitečných" objektů šablonový "invazivní" reference counting objekt, který tuším navíc obsahoval zámeček... aby ten reference counting fungoval z více vláken, a aby fungovalo "poslední zhasne" = po dekrementaci ref.counteru na nulu se objekt dále prostřednictvím zmíněného invazivního reference counteru sám destruuje... jde pouze o to zařídit, aby po dealokaci paměti
dobíhající member metoda už nesáhla do dat nyní již neexistujícího objektu :-) = dealokace dělat až těsně před návratem.
Podobně zábavné situace "slepice nebo vejce" nastávají při graceful shutdownu a řízenému zastavení všech vláken hlavní smyčkou programu, kterou přerušil signal handler apod. Resp. zařídit, aby došlo ke graceful shutdownu jak při zastavení vnějším povelem, tak při zastavení spontánním (vlákno zjistí chybu a proto se samo ukončí, případně to napřed nějak nahlásí).
Řekl bych, že tahle práce "bolí, ale hezky" :-) Ladit ty vejce a slepice je někdy záhul na mozkovnu. Ale je super, když to po vyladění celé chodí jak hodiny. A naopak není vůbec super, když to napíšete a odladíte na nějakém stroji/procesoru, pak to spustíte na jiném s troji s jiným počtem jader apod., a ono to začne padat, protože se změní "charakter konkurentního běhu více vláken" v těsném okolí zamykaných kritických sekcí :-) Je to *hodně* náročné na předvídavost a pečlivost při psaní kódu. A je to potenciálně veliká zábava.
-
private fields can't be accessed with reflection
Tahle diskuse mě přestala bavit, jako obvykle vyletěla z věcných kolejí. Pravda je, že Go to neumí zajistit v době překladu, a u cizího kódu není garantováno v podstatě nic. V takové situaci, kdybych chtěl mít stoprocentní jistotu, bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného, který bych si nadefinoval sám ve svém kódu, abych měl zajištěno, že mi na něj nebude nikdo nijak šahat po tom, co ho pošlu kanálem, ať už kopií nebo jen ukazatel na něj, to je fuk. I výkonostně to je ostatně podstatně efektivnější než reflexe. Ovšem úplně nejlepší řešení by bylo použít Rust nebo ten Erlang :)
-
bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného
Což právě ten příspěvek, na kterej reaguješ, konstatuje, že nejde ::)
To není vypadnutí z věcné koleje, to je totální neschopnost naslouchat argumentům, vyhodnocovat je a reagovat na ně.
-
bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného
Což právě ten příspěvek, na kterej reaguješ, konstatuje, že nejde
Je to marný, je to marný, je to marný :-\
-
Je to marný, je to marný, je to marný :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger
-
Je to marný, je to marný, je to marný :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger
Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.
Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.
-
Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.
Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.
To už pár let není jediné možnost, AFAIK.
-
Je to marný, je to marný, je to marný :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger
Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.
Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)
Rust nepoužívám a nijak podrobně neznám, ale co jsem tak postřehl, dostal teď async/await, takže nejspíš dostává kooperativní korutiny (jako C#, C++(20) nebo to Go).
Edit: https://www.i-programmer.info/news/98-languages/14282-asysnchronous-runtime-for-rust-released.html
-
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)
Za prve: Kterou cast prispevku
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.
jsi nepochopil?
Za druhe: ne, neni to nijak zvlast neotrele. Pouzil jsem to jako priklad, protoze presne tohle mam v kodu pred sebou. Jsou tam nejake "objekty" (implementovane samozrejme strukturou), u kterych se nekde na zacatku kodu inicializuje logger. Ten se pak vlozi do struktury, aby si kazdy "objekt" mohl logovat tak, jak bylo na zacatku nastaveno.
Co je na tom "neotreleho"? A co je tak skandalniho na myslence, ze bych si chtel tenhle objekt nekam poslat channelem?
A vubec nejzasadnejsi otazka: proc tak urputne obhajujes neco, co zjevne ma svoje mouchy? Proc nemuzes proste priznat "jo, neni to idealni, slo by to udelat lip"? Ses ted jako placenej ambassador Go nebo jak?! Nechapu to. Pripominas mi javascriptare, kteri urputne obhajuji, jak je == v JS uplne v pohode a nema zadny problem.
::)
-
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku (https://www.linux.cz/noviny/1998-0809/clanek11.html). Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál.
Ještě jsem si vzpomněl, že jsem možná první zmínku o libpthread a vláknech četl v papírovém vydání "Linux - začínáme programovat", někdy v roce 2000. A jak jsem při následném online studiu užasl, že v té knížce úplně vynechali podmínkové proměnné (conditional variables). A teď vidím online 4.vydání v PDF, a v kapitole 12 dodnes není ani zmínka o podmínkových proměnných :-) (https://doc.lagout.org/operating%20system%20/linux/Beginning%20Linux%20Programming%2C%204%20Ed.pdf) Ostuda. Listuju v papírové knížce a našel jsem jako záložku svůj papír, kde jsem si průchod dvou vláken "synchronizací s podmínkovou proměnnou" načmáral :-) A vytištěnou stránku z Linux Standards Base reference, která obsahuje seznam funkcí libpthread (https://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/libpthread.html#AEN14954).
-
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku (https://www.linux.cz/noviny/1998-0809/clanek11.html). Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál.
Ještě jsem si vzpomněl, že jsem možná první zmínku o libpthread a vláknech četl v papírovém vydání "Linux - začínáme programovat", někdy v roce 2000. A jak jsem při následném online studiu užasl, že v té knížce úplně vynechali podmínkové proměnné (conditional variables). A teď vidím online 4.vydání v PDF, a v kapitole 12 dodnes není ani zmínka o podmínkových proměnných :-) (https://doc.lagout.org/operating%20system%20/linux/Beginning%20Linux%20Programming%2C%204%20Ed.pdf) Ostuda. Listuju v papírové knížce a našel jsem jako záložku svůj papír, kde jsem si průchod dvou vláken "synchronizací s podmínkovou proměnnou" načmáral :-) A vytištěnou stránku z Linux Standards Base reference, která obsahuje seznam funkcí libpthread (https://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/libpthread.html#AEN14954).
Klasické synchronizační vzory jsou výborně popsány ve free knize Little Book of Semaphores: https://greenteapress.com/wp/semaphores/ . Vždy jsem tam našel co jsem potřeboval.
-
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)
Za prve: Kterou cast prispevku
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.
jsi nepochopil?
Za druhe: ne, neni to nijak zvlast neotrele. Pouzil jsem to jako priklad, protoze presne tohle mam v kodu pred sebou. Jsou tam nejake "objekty" (implementovane samozrejme strukturou), u kterych se nekde na zacatku kodu inicializuje logger. Ten se pak vlozi do struktury, aby si kazdy "objekt" mohl logovat tak, jak bylo na zacatku nastaveno.
Co je na tom "neotreleho"? A co je tak skandalniho na myslence, ze bych si chtel tenhle objekt nekam poslat channelem?
A vubec nejzasadnejsi otazka: proc tak urputne obhajujes neco, co zjevne ma svoje mouchy? Proc nemuzes proste priznat "jo, neni to idealni, slo by to udelat lip"? Ses ted jako placenej ambassador Go nebo jak?! Nechapu to. Pripominas mi javascriptare, kteri urputne obhajuji, jak je == v JS uplne v pohode a nema zadny problem.
::)
Jsem překvapen, ale zcela souhlasím s Mirkem. Pokud je to aspoň trochu praktické, naprosto preferuju compile-time safety před runtime asserty, unit testy, štábní kulturou, selským rozumem a podobnými věci, na které je ošemetné se spoléhat. V tomto smyslu je určitě Rust nebo Elixir napřed před Go.
-
Si to ještě jednou pozorně projdi, opakovaně jsem psal, že to v Go v době překladu nejde a že const/initonly by se šiklo. Jinak je mi Go celkem ukradené, když už, má mnohem horší WTF vlastnosti než posílání ukazatelů kanálama. Vzhledem k tomu, že tvoje příspěvky jsou čím dál tím slabomyslnější (nevím, proč tě baví trollení, ale to je fuk), dodrž, číms vyhrožoval (omez příspěvky na nula).
-
Pokud je to aspoň trochu praktické, naprosto preferuju compile-time safety před runtime asserty, unit testy, štábní kulturou, selským rozumem a podobnými věci, na které je ošemetné se spoléhat. V tomto smyslu je určitě Rust nebo Elixir napřed před Go.
Na tom se tu evidentně všichni shodneme.
-
Si to ještě jednou pozorně projdi, opakovaně jsem psal, že to v Go v době překladu nejde a že const/initonly by se šiklo.
Jenze ono (AFAIK) to nejde ani v runtime. Cili za nevhodne shody okolnosti se muze stat, ze to na produkci bude padat nebo kryplit data. Nebo nebude. Uvidi se. V produkci.
A proto tvrdim, ze kanaly v Go nejsou ani bezpecne, ani blbuvzdorne, to je od zacatku moje teze. Opakovane jsem te vyzyval, ze jestli s necim nesouhlasis, mas moznost ukazat kod. Neudelals to.
Vzhledem k tomu, že tvoje příspěvky jsou čím dál tím slabomyslnější
Tahle diskuse mě přestala bavit, jako obvykle vyletěla z věcných kolejí.
::)
-
Pokud je to aspoň trochu praktické, naprosto preferuju compile-time safety před runtime asserty, unit testy, štábní kulturou, selským rozumem a podobnými věci, na které je ošemetné se spoléhat. V tomto smyslu je určitě Rust nebo Elixir napřed před Go.
Na tom se tu evidentně všichni shodneme.
No nevím. Ve vašich příspěvcích v tomhle vlákně to teda moc vidět není.
-
Klasické synchronizační vzory jsou výborně popsány ve free knize Little Book of Semaphores: https://greenteapress.com/wp/semaphores/ . Vždy jsem tam našel co jsem potřeboval.
Musím uznat, že to je vypadá jako milá knížečka :-) Se svými 300 stránkami není úplně maličká, ale tím líp. A dokonce tam kolem vidím pár dalších spisků téhož autora, na potenciálně zajímavá témata, všechny volně k dispozici... to zas bude mít rodina zlost, že si furt jenom čtu :-/
Díky :-)