A lemonbar nevű panelt használom Linuxon. Ez egy egyszerű alkalmazás, amibe be kell pipe-olni \n karakterrel lezárva, amit kiírjon, és azt kiteszi az X root képernyő tetejére egy sávba. Így írtam egy shell szkriptet, ami 0,5 másodpercenként kiírja az adatokat, ami a nyitva maradt pipe-on eléri a lemonbart. Ezzel nincs is baj, világos a működése, de egyes kiírt dolgok változhatnak idő előtt, mielőtt a szkript magától frissítené/lekérdezné őket, újra kiírná az adatokat. Ezt úgy oldom meg, hogy a "sleep 0.5" folyamatot pkill-lel kilövöm a kiírt adatok változását okozó esemény után, ami egy külön szkriptben történik (sxhkdrc). Ez alapvetően így működik is, de a panel még mindig kicsit lassan frissül, jó pár ms-os késéssel változik rajta az információ, közel fél másodperc.
Ami a kérdés lenne: ezt más lemonbar felhasználók úgy oldják meg, hogy a szkriptjük a kiírandó adatokat (hangerő, idő, stb.) egy előre, név szerint, az mkfifo paranccsal a /tmp/-be bizonyos létrehozott pipe-ba irányítják, és a lemonbar-nak csak egy a pipe-ot fprint-elik bele újabb pipe-on át:
#!/bin/sh
# bla-bla, nem érdekes részek
fifo="/tmp/panel_fifo"
mkfifo "$fifo"
# bla-bla-bla, újabb kódrészek, majd a fő while do loop végén ez jön
printf "%s\n" < "$fifo" | lemonbar
Ez mitől lenne gyorsabb, mint az én megoldásom? Csak simán pipe-olok bele a lemonbarba:
while-do-echo-szkriptem | lemonbar -kapcsolók &
Elvileg ez a hagyományos pipe-olás is a memóriában létrejött csatornába íródik, így nem értem, hogy az én megoldásomtól miben lenne jobb ez a /tmp/-be fifózás. El tudná magyarázni nekem valaki, mielőtt több órát vergődök egy újabb scriptes konfiggal? Még nem próbáltam ki, de mindenütt azt írják a neten, hogy ez a fifós megoldás gyorsabb. Először arra gondoltam, hogy a megoldásom valahol máshol selejtes, de nem, mert tényleg frissül a panel, kilövi idő előtt a szkript várakozási sleep folyamatát (ezt teszteltem), és mégis kicsit lassú. Próbáltam úgy is, hogy közvetlenül az adatváltoztató esemény előtt és után is kilövöm a sleep-es folyamatot, biztos, ami biztos, de az se gyorsít a panelfrissítésen. Gyakrabban nem akarom frissíteni fél másodpercnél az infókat, mert akkor az már túl nagy prociterhelés egy egyszerű panelért.
Hozzászólások
Például mert nem indít mindig újabb processzt?
Gábriel Ákos
Hozzál nekem a boltból egy lekváros buktát! Öööö.... :-D
Ha nem csukod be a szádat, akkor éhen maradsz!
Itt is ez a helyzet. Ha a fifo másik oldalán kukkoló ellenséggel nem beszélted meg, hogy az ööö... nálad a parancs vége, akkor még várakozni fog, hátha mondasz valamit.
A printf kezdetű sor kiolvassa a $fifo-ból az üzenet(ek)et, majd becsukja a száját, azaz küld egy EOF-ot a végén.
A programod egy fifo-n keresztül (a | is egy fifo, csak nincs neve) üzenget, de soha nem küldi az EOF-ot. Így aztán a lemonbar gondolkodok, gondolkodik és közben vár. Egy idő után rájön, hogy ez a hülye csak nem csukta be a száját és végrehajtja az olvasott utasításokat. ;)
Nem az a lényeg, hogy a parancsokat fifo-ban, fájlban vagy zacskóban gyűjtöd, hanem átadáskor jelezni kell a végét!
Ok, kösz szépen, erre voltam kíváncsi, mert nem ismerem a fifo-k és a shell lelki világát ennyire mélyen. Elvileg a lemonbar nem az EOF-ot nézi, hanem a \n karaktert (amit elküldök, nem kifejezetten \n segítésével, hanem az echo parancs küldi default), de könnyen meglehet, hogy az EOF is segíthet rajta sebességügyileg, így mindenképp kipróbálom ezt a printf < $fifo megoldást, ha tényleg gyorsít.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Megnéztem a lemonbar forrását - bocsánat, tévedtem.
A fifo-val működő megoldásnak teljesen más oka van. A fifo ebben az esetben csak egy buffer, amibe aszinkron lehet írogatni a parancsokat, majd egyszerre bezuttyantani őket a lemonbar felé.
A printf "%s\n" < fifo extra \n karaktert ír a parancsok után. Itt jobb a cat vagy a printf "%s".
Mégegyszer végigolvastam a kérdést. Talán egy kicsit túlbonyolítod a dolgot. A sleep nem alkalmas pontos időzítésre, nem így kellene megoldani, meg még lőni is rá. ;)
Inkább eseményvezéreltté kellene alakítani a programodat. A sleep lejárta is egy esemény, meg a hirtelen tennivaló is esemény - mindegyik írhat azonnal, ha kell.
Gyakorlatilag pont ezt írtam, csak a szakkifejezést nem használtam :)
OK, én nem tudom, hogy a mester min erőlködik. ;)
Ha külső hatások is vannak, akkor célszerű az eseményeket elkapni és végesállapotú géppel (FSM) (automata) feldolgozni. Tudok ám még néhány szakkifejezést! :-D
Itt már pont ezt írja. De azért örülök, hogy nem csak én gondolom, hogy ezt így meg lehet oldani - akár ismeri a szakkifejezéseket, akár nem :D
A külön script hatására újabb szakkifejezések tolulnak fel bennem: multitasking, background process, coprocess, separate subshell. :-D
Nem tudom, hogy sikerült így félreolvasni, de a coprocess és a separate subshell valahogy corporate bullshit-té alakult. :))
Debian - The "What?!" starts not!
http://nyizsa.blogspot.com
Rendben, kösz a helyesbítést. Még nem volt időm tesztelni, de megejtem. A lényeg, hogy javíthat a panelfrissítési időn. A \n elvileg kell a lemonbarnak, mert onnan tudja, hogy megvan minden adat a panelre, de lehet megfelel neki az EOF is, a kódját nem tanulmányoztam alaposan. Az a baj, hogy a dokumentációja nem a legjobb ennek a programnak, kitér ugyan a konfigolására, de nem tér ki a frissítésre, meg mélyebben a működési elvre.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Most volt időm hétvégén kipróbálni. Igaza van, ez a fifo-zás csak arra jó, hogy aszinkron lehessen frissíteni az egyes elemeket a baron. A frissítési problémát épp úgy nem oldja meg, mert ez is sleepeket használ. Egyelőre az eseményfigyelést nem próbáltam ki, ott lesz a megoldás kulcsa.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
A dzen2 is hasonló elven működik, én azt használom (még nem volt érkezésem lemonbar-ra átírni).
Hasonló problémába én is belefutottam (tehát megtörtént valami változás és az késve íródik ki). Én azt csinálom, hogy a szkriptek, amik a változásokat figyelik, egy jelet küldenek, hogy változott, és csak akkor generálok új sort (ami a régit felülírja). Azaz ha van lehetőséged, akkor keress egy olyan hangerő-kezelőt, ami lefuttat egy parancsot, ha változott a hangerő. Vagy ha tuti biztos vagy benne, hogy csak hotkey segítségével (pl. xbindkeys) változtatsz hangerőt, akkor legyen ebben is egy jel küldve a lemonbar felé - ezáltal nem kell x másodpercenként ellenőrizgetni feleslegesen.
Másik lehetőség: pl. conky-val generálod a lemonbar-nak az inputot.
Conky-t nem szeretnék, felesleges extra lenne, de ezt a másik megoldásod kipróbálom, hogy külön scriptbe kitenni az egyes infókat, és azok jelezzenek, ha van változás.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Ezt a jelet hogy küldöd el a scriptnek? Mármint konkrétan milyen megoldással, valami signal, vagy változót vagy fájlt módosítasz?
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Ha elég a script, akkor tanulmányozd a trap parancsot!
Ehhez tudnál valami konkrétabban tanácsolni? Hogyan paraméterezzem a trap parancsot, ha azt akarom, hogy pl. a SIGUSR1 szignálra indítsa újra az adott scriptet, vagy akár csak egy al-shellben futó függvényt?
Gyanítom, hogy az általam már linkelt netes szkript is valami ilyesmit csinál ebben a sorban, de nem pontosan értem a parancs részleteit:
trap 'trap - TERM; kill 0' INT TERM QUIT EXIT
Annyival tisztában vagyok, hogy a trap parancs után az első paraméter elvileg egy parancs (amit végre kell hajtani), a második paraméter a szignál, amire a parancs triggerelődik. De még nem vitézkedtem ezzel soha, így az apró trükkjeit nem ismerem. Talán csak egy régi szkriptemhez kukáztam össze ilyet a netről, amiben csak annyi kellett, hogy maga a szkript ne reagáljon a SIGKILL és SIGTERM szignálokra.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Ennek utána kellett néznem, mert ilyet csak C-ben írtam.
Ajánlom ezt és ezt. (végigolvasni!)
Ez a programod modellje - lehet tolni tovább a lemonbar felé.
A program 30 másodpercenkén tesz egy kört és kiírja a "Sleep over" üzenetet. Ez a periodikus tevékenység helye.
Ha küldesz egy SUGUSR1-et, akkor megszakad a wait - a biztonság kedvéért kilövi a sleep-et - és a "Caught SIGUSR1" üzenetet írja ki. Ez a külső esemény hatására végzendő tevékenység helye - vagy a do_nothing.
A futás (a promptot kitöröltem, a > a kézzel kiadott paracsot jelenti):
Kösz szépen, ki fogom próbálni, mert a saját megoldásom nem működik. Elkapja a scriptem az SIGUSR1 szignált (nem muszáj ennek lennie, tőleg lehet USR2, vagy akármilyen más értelmes szignál is), de leáll rá. Gondolom azért, mert a fő loopon kívül vizsgálom, és emiatt megszakítja a fő loopból, nem lépve bele vissza. A te megoldásod a fő loopban vizsgálja, így tényleg megoldás lehet.
Közben rájöttem, hogy a linkelt szkriptben mi az a furcsa trap - sor. Lényegében az azt csinálja, hogy ha kívülről kilövik a lemonbaros szkriptet, akkor az által hívott, subshellekben futó loopok is bezáródnak vele együtt, egyébként azon nyitva maradnának, teleszemetelve a memóriát.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
A trap - SIGNAL törli a korábban SIGNAL-hoz rendelt handlert. (Subshellek meg loopok! :( Inkább át kellene gondolni mit csináljon a program, mintsem a "majd alkalmazok egy olyan parancsot, amiről azt sem tudom mire való".)
Az "én megoldásom" a programod modellje - signal handlerrel kiegészítve. A teszt futtatásban (ami background) a kézzel kiadott kill a "külső esemény". Erre való pl. a /tmp/pidfile (amibe beleírod a szkriptből a $$ értékét), hogy a "külső ellenség" tudja hova lőjön.
És erre való a bash emulált EXIT signal: trap "rm -f /tmp/pidfile" EXIT
Végigolvastam a két linket, és az elsőn azt írják, amit már sejtettem. A USR1 szignálra beindul a handler shell függvény, amit megadtam neki, de cserébe abbahagyja a szkriptem fő loopját, és abba nem tér vissza. Ezt ki lehetne úgy védeni, hogy a handlernek megadott egy újabb függvényt, ami az eredetileg kívánt függvényt hívja és a loopot is újraindítja.
Amit még nem értek: a példádban a sleep-nek a USR1 szignálra való kilövése mitől jobb vagy gyorsabb, mintha magát a sleep folyamatát lőném ki kívülről, szignálozás nélkül?
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Próbáld meg a link helyett a fenti programot futtatni. ;)
Ott van alul a futás eredménye is. Hol lép ki???
A probléma a "sleep folyamatát lőném ki kívülről" dologban van. Vajon hány szkriptet szertnél írni, amikor egyet sem látsz át?
Ott van, amit írtam, az potosan a szkriptednek a modellje. A signal handler nem hagyat abba semmit, csak az éppen hosszabb ideig futó parancsot. Esetünkben sajnos a sleep nem ilyen, ezért kell a sleeep 30 & ; wait kombó. Tehát a wait kilép, lefut a handler, majd a wait utáni soron folytatódik.
Az első program működése: 10 másodpercenként frissít, de ha külső esemény jön, akkor azonnal frissít és újrakezdi a 10 másodperces kört.
Itt egy másik változat, ami: 10 másodpercenként frissít. Ha külső esemény érkezik, akkor beiktat egy extra frissítést, de nem lő ki semmit.
A futás:
Szerinted ez hol lép ki? (A végén a ^C hatására.)
Igazad van, ez lefuttatva tényleg működik, csak azt nem értem, hogy mi hajtsa ki belőle a zoxigént. Vagyis, hogy pl. wait nélkül, az előtérben futó sleep-pel ez miért nem működik, miért lenne a sleep ilyen szempontból speciális Azt még értem, hogy a wait azért kell, mert a sleepet a háttérben futtatod, de te azt nem érted, amit én nem értek, hogy minek kell a háttérben futtatni. Most lehet én vagyok gyp-s, de magas ez nekem.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Futtassuk a p1 programot, majd egy ps!
A kill -SIGUSR1 9556 esetében a PID stabil, míg a sleep (/bin/sleep - external parancs) PID minden loopban más lesz.
Ezen kívül a p1-ben (PID=20665) van SIGNAL handler, de a sleep-ben nincs signal handler. A wait pedig (bash) internal parancs, így a bash meglövésével kilép és a handler végrehajtása után folytatja a script következő soránál.
Tehát ebben az esetben implementációfüggő, mert nincs sleep internal parancs.
A C/multithread környezetben nincs ilyen probléma, mert csak egy program space van, tehát
Higgyél nekem, már 30 éve csinálom! ;) (A Die Hard mintájára.:))
Bár a tudásomat inkább az AIX dokumentációból szereztem - az hatékonyabb, mint a fórum. ;)
Az ablakkezelő segítségével. A herbstluftwm-nek van egy kliensprogramja is, aminek van idle opciója, ami annyit csinál, hogy várakozik, amíg esemény nem jön. Eseményt saját kezűleg is kiválthatsz (emit_hook). Miután kapom az eseményt, a megfelelő infót frissítem, a többit pedig az eltárolt változókból előszedem, és kap a bar egy új sort.
Azért az ablakkezelőt használom erre, mert különböző ablakkezelős eseményeket is le lehet így "hallgatni", és reagálni rá (pl. a conky észrevehetően később frissült, mikor pl. munkaasztalt váltottam) - és minek legyen kettő eseményvezérlés, ha egy is lehet.
Szerk.: lényegében a szkript (leegyszerűsítve):
Kösz a válaszokat. Egyelőre a signal küldést fogom kipróbálni trap-pel, ha az nem jön be, akkor ezt a /tmp/-be fifózást, és a fifo-buffert figyelem, hogy változott-e, ez akár az entr nevű toollal is figyelhető. Ha az sem, akkor megpróbálom ezt a herbstluftwm-es megoldást, bár ettől azért ódzkodok, mert WM-független megoldást keresek.
Lassan ott vagyok már, hogy kezd belőle elegem lenni egyébként, és visszacsábulok polybar-ra, ami ezeket a low level kérdéseket kulturáltan megoldja, és nem a usernek kell vele vergődni. Más részről viszont a polybart kicsit blaotnak tartom, messze nem használnám ki a tudását (ugyanez a bajom a Conky-val is), erre a lemonbar-ra pont azért álltam át, mert minimalistább, és nekem elég is lenne, ha ez a frissítési mizéria nem lenne vele. Nekem a dwm beépített bar-ja is elég volt, szóval azért erőltetem a lemonbart.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
A herbstclient --idle részt helyettesítheted bármivel, akár pl. egy FIFO-ból való olvasással is. Ekkor nyilván a FIFO-ba fog menni az "esemény" is. És ezzel kész a WM-független megoldás :)
Most már kezdem érteni. Nem kell nekem semmilyen herbstlicent. A while read line < $fifo elég nekem, a read parancs ilyenkor szépen kulturáltan, prociterhelés nélkül vár, amíg nem lesz a fifo-ban új adat.
Sőt, már azt is gyanítom, hogy nekem miért frissült lassan a lemonbar (procipörgetési problémán kívül is): mert az egyes kiírt infókat lekérdező parancsok az én szkriptemben sorban futottak le, négy modul a fő loopon belül: echo "$(modul1_fuggveny) ($modul2_fuggveny) ($modul3_fuggveny) ($modul4_fuggveny)". Ebben a felállásban a parancsok egymás befejezésére várnak, a soron következő parancs addig nem fut le, míg az előző be nem fejeződött, ez volt az oka a lassúságnak, ennyi parancsnál már összehalmozódtak annyira a varákozási idők, hogy késleltetésként jelentkezett. Az általam linkelt cikkben lévő, fifo-ba írogató, háttérben asszinkron frissítő modulok ezt is megoldják.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Igen, ilyesmire gondoltam. A lekérdező parancsok futtatásának idejét úgy spórolom meg, hogy a dzen-nek (esetedben lemonbar) küldött sztringbe a változatlan infókat a szkriptben eltárolt változókból szedem.
Közben annyival is előrejutottam, hogy a szkriptemben nem kell egy csomó modulnál sleep-eznem, sem figyelnem, hogy változott-e. Kiderült, hogy az xtitle alkalmazásnak van például -s kapcsolóra egy snoop módja, ami prociterhelés nélkül kiírja újra a fókuszban lévő ablak nevét, ha az megváltozott. Ugyanígy a bspwm-ben lévő bspc subscribe parancs is folyamatosan tudja figyelni az aktív munkaasztalt, ha megváltozott, akkor új sorba írja kimenetnek. Az időt 1 másodpercenként frissítem (bár lehet elég lenne a 60 sec is, és jobb lenne csak a percre pontosan írni), ez sem akkora terhelés.
Egyedül az van, amit írsz, hogy a hangerőt kéne kulturáltan, prociterhelés nélkül, sleep utáni felesleges újralekérdezés nélkül figyelni. Erre nem találok megoldást, pedig kell, hogy létezzen.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Két lehetőséget látok: ha biztosan tudod, hogy csak hotkey segítségével változtatod a hangerőt, akkor arra nem csak a hangerő változást rákötni, hanem az "esemény küldését" is. Másrészt meg kell nézni, hogy milyen hangrendszered van (gondolom, pulse, de azt se tudom, milyen linuxot használsz), és ott szétnézni, van-e esetleg ilyesmi parancs, amiket most írtál (pl. xtitle esetén a -s illetve bspwm-ben a subscribe).
Közben megvan a hangerő is:
pactl subscribe | grep sink > $fifo_nev
Így az órán kívül semmit nem kell már sleep-pel frissítenem, mindennek a változását tudom detektálni, CPU pörgetése nélkül a fifo-ból, ilyen subscribe-os és snoop-os megoldásokkal.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Az óraváltásra: ha esetleg más nem, azt is csinálhatod, hogy egy percenkénti cron-t hozol létre (ha nem szükséges a másodpercenkénti kijelzés), amivel eseményt váltasz ki :)
Azt inkább nem, az nagyon bonyolult. Maradok az egyszerű megoldásnál:
while true; do date "+formatumfelsorolas"; sleep 1_vagy_60; done > $fifo_nev &
Egyelőre eddig beválik, ezekkel a snoopingolós újításokkal és a fifo-ba asszinkron írogatós, majd while read line; do ...; done segítségével feldolgozós megoldás segített a problémán. A prociterhelés 0-ra ugrott vissza, és minden eseményre azonnal, villám módon reagál és frissül a panel. Nem kell hozzá sleep, nem kell hozzá -USR1 szignálfigyelés.
A hangerőfigyelés nem tökéletes. A pactl subscribe | grep sink parancs két soronként írogat a fifo-ba (a pactl a bal és jobb hangerőcsatornára is logolja a hangerőváltozást), és ez bezavar a read line parancsnak, ami meg soronként olvasna, így a hangerő nem frissül a panelen. Próbálkoztam, hogy head -n1 pipe-olást iktatok közbe, az se segített. Próbálkoztam grep -m1 kapcsolóval, de az se segít.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Akkor azt még meg kell masszírozni, ha más nem:
Ááá, megvan! Kellett a grep-nek a --line-buffered kapcsoló, így már működik a megoldásod:
pactl subscribe | grep --line-buffered sink | sed 'N;s/\n/,/'
Enélkül a kapcsoló nélkül csak 4096 bájtonként írogat a grep kifelé, előtte csak bufferbe gyűjtöget. Ez általában nem gond, mert csak egyszer futtatja az ember, és nem folyamatos pipe-ban eteti. Sőt, kiderült, hogy még a sed se kell, nem zavarnak be a dupla sorok, ha van ez a line-buffered kapcsoló. Jó tudni, mert még sose kellett.
“The world runs on Excel spreadsheets.” (Dylan Beattie)
Még egy pár gondolat, nem a shellszkriptes részéhez, hanem a lemonbar-hoz. Szerintem nem érte meg. Minimalistább, mint egy polybar, de cserébe nehezebb konfigolni, script kiddie-nek kell hozzá lenni, fontkezelése korlátos. Most, hogy így be van konfigolva végre (awesome font-os ikonokat nem tudtam még úgy összehozni, hogy függőlegesen jól legyenek pozicionálva), összesen eszik 20 MB körül a memóriából. A polybar evett 25-27 körül, de cserébe sokkal szebbre bekonfigolható, könnyebb is a konfigolása, mivel sok kész modul van hozzá, amik trükközés nélkül, épp úgy CPU terhelés nélkül ki tudnak mindent jelezni.
Most is bejött az, hogy a minimalizmusnak megvan az a foka, ahonnan nem éri meg. A dwm-nél is ezt éreztem. Oké, minimalista, de mire az ember hozzáadja a szükséges patcheket és billentyűkombókat, bekonfigolja a paneljét, a végén majdnem ott van memóriafogasztásra, mint egy bspwm lemonbar-ral és sxhkd-vel, cserébe a dwm elég korlátos, míg a bspwm-nek van rendes szerver-kliens socket protokollja, amin keresztül lehet üzengetni neki bspc-vel (és így bármilyen szkriptnyelven lehet konfigolni akár még menet közben is, újraindítás nélkül), támogat EWMH protokollt, aminek mentén xdotool-lal és hasonlókkal is távirányítható, plusz a multimonitor-támogatása is jobb (jó, ezt a részét nem használom). Cserébe alig eszik pár megával többet, de az egész sokkal rugalmasabb. Ilyen kevés MB különbözet még egy nagyon gyenge gépen sem éri meg spórolni szerintem.
Gentoo-val szintén ugyanez volt a bajom. Ki lehet vele hagyni a sysmted-t, initramfs-t, meg le lehet spórolni pár függőséget, pár MB RAM használatot, de az egésztől nem lett gyorsabb a gép, csak ez ember forráskódot pörgettyűzik órákon át, nyereség meg már nincs rajta több egy Arch-hoz, Void-hoz képest, cserébe még néhol lassabb is. Linux from Scratch-ról ez még hatványozottabban elmondható.
Emiatt ezt a lemonbaros konfigolást kicsit felesleges körlefutásnak érzem. Nem teljesen azért, mert mégis csak minimalistább, kevesebb a függősége, bármilyen rendszeren könnyebb leforgatni forráskódból (ez pl. számít BSD-ken), plusz most már hogy jobban tudom konfigolni, ugyanezt a tudást a dwmbar-ra és dzen2-re is át lehet vinni. Plusz a szkriptekről, grep-ről, stb. is tanultam egy csomó érdekes dolgot.
“The world runs on Excel spreadsheets.” (Dylan Beattie)