Newsgroup: it.comp.lang.perl
Titolo: mi suggerite alcune soluzioni in Perl?

Ciao a tutti.
Recentemente ho trovato il pretesto di scrivere un bot irc che veicoli
alcuni servizi anche con lookup a tabelle SQL. Avevo gia' dei framework
ben funzionanti scritti tempo fa in C, ma la mia recente scelta strategica
sul perl mi ha fatto sentire la necessita' di riscriverli, scoprendo pero'
che non padroneggio cosi bene il Perl e non riesco a tradurre in modo perl
una soluzione soddisfacente in C.
Preludio: il processo principale (sistema Linux) che si connette al server
IRC si blocca su select a cui passo un set di connessioni che inizialmente
e' costituito della sola socket, ma che processando i comandi potrebbe
generare altri processi con cui rimane in collegamento con pipe() o
socketpair(). Tali processi potrebbero essere bloccanti si query MySQL
quindi questo e' un espediente per non bloccare il processo principale
(credo che la connessione restituita dal modulo DBI non sia utilizzabile
con select())
Quindi il set passato a select() si arricchisce temporaneamente e
dinamicamente di filedescriptions delle pipe() con i processi "server"
generati per l' occasione.
Tutte le scelte solo conseguenti: Con select() si deve usare IO non
bufferizzato e io ho scelto sysread e syswrite.
Tuttavia devo leggere linee e non blocchi e comunque leggere da un socket
con <SOCKET> e' pericoloso, oltre che facente uso di read bufferizzata.
1) in C con l' algebra dei puntatori e il modo efficiente di fare lookup
 a singolo carattere non e' un problema, ma in perl? substr() la
escluderei,
 forse index(), ma io ho preferito questo approcio:
 leggo un buffer con sysread() di MAX 8192,
 @array = split /(/r/n)/ , $buffer;
 # con le parentesi split genera @array con
 "linea1","/r/n","linea2","/r/n", ...)
 quindi le l' ultima linea e non-equal "/r/n" non la processo
 perche' incompleta e la concateno al prossimo buffer letto e
 rivado di split()
 Si puo' fare di meglio in termini di cicli macchina??
2) Alcuni comandi ricevuti in privmsg possono attivare transazioni
 che richiendono l' invio di altri comandi. se questi non arrivano
 al timeout viene azzerata la transazione.
 allo scopo passo a select() un timeout estratto dalla cima di una coda
 inizialmente contenente solo undef(), ma che dinamicamente
 puo' riempirsi di timeouts successivi cronologicamente.
 la coda quindi deve essere sempre ordinata per tempo assoluto,
 per poi passare a select la differenfa con Time::HiRes::time();)
 Questa necessita' di avere caratteristiche ordinali per i timeouts
 mi costringe ad optare per un array, ma associato ad ogni valore
 (array parallelo o array di reference ad arrays non importa) devo
 avere la sua routine di gestione con i relativi argomenti.
 Fin qui nessun problema, ma per rimuovere un timeout dalla coda in modo
 efficiente come trovarlo?
 Ho pensato di associara ad ogni timeout una key univoca di numero di
 tranzazione, ma l' unico modo che ho trovato per selezionare uno
 specifico record e' quello di scansionare l' array e poi fare splice().
 non e' un problema visto l' ordine di grandezza (poche decine MAX spero)
 ma essendo appassionato di programmazione chiedo se esiste una tecnica
 piu' scalabile usando gli strumenti Perl. Non sono riuscito ad adattare
 gli hash a questo scopo.
Altra cosa. Se un processo Perl rimane attivo per mesi o anni, qualcuno
ha notizia di problemi al memory manager? array che cambiano di numero
elementi, scalari che si ridimensionano ecc.. potrebbero impegnare tutta
la ram di sistema e rentere necessario il riavvio?
Avrei altro da chiedere ma per oggi il mio contributo per ravvivare il NG
e' sufficiente.
Ciao a tutti.
Roberto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 alcuni servizi anche con lookup a tabelle SQL. 
Io ti consiglio, se non l'hai già fatto, di cercare su CPAN.
Ad esempio trovi diversi moduli per interagire con IRC:
POE::Component::IRC
Net::IRC
Bot::BasicBot
IRC::Bot

 IRC::Bot
Non dubitavo di CPAN.
Mi rendo conto che non sono stato chiaro. i problemi di programmazione
su cui ho chiesto consiglio sono piu' generali e svincolati dalla
realizzazione di un bot.
Problema 1:
Voglio acquisire input con sysread da qualsiasi stream (socket, pipe ecc.)
in uno scalare di MAXBUFFER ed elaborarlo per linee. NON VOGLIO acquisirlo
con readline per ragioni di sicurezza e perche' l' uso di select() esige
per chiari motivi l' uso di IO NON bufferizzato.
|--------\r\n---| |-----\r\n------\r\n------| |--------| |------\r| |\n---|
cioe' elaborare subito quando disponibili le linee complete e gestire il
resto. Gia' l' ho risolto con:
while (ciclo di select())
{
....
  sysread $socket, $buffer,8192;
  @linee = split(/(\r\n)/,$buffer);
  $incompleta = $incompleta . shift @linee;
  if (length($incompleta) <= 8192)
    { unshift @linee, $incompleta; }
     # non ammetto linee troppo lunghe
  if ($linee[$#linee] ne "\r\n")
    { $incompleta = pop @linee; }
  else { $incompleta = ""; }
  for my $str (@linee)
    { ..... }
....
}
solo mi sembra strano che in perl non si possa fare in altro modo,
ma mi accontento.
--------------
Problema 2:
Select() e' bloccata su un set di Filedescr e Sockdescr e in attesa
di un timeout. Ogni folta che scade timeout eseguo la routine associata
passandogli gli argomenti associati.
Il problema e' la manutenzione di un array di timeout efficiente.
1 --> sub1 arg 1
5 --> sub5 arg 5
7 --> sub7 arg 7
8 --> ecc...
16 --> ecc...
20
ad un certo punto so' che il timeout 7 non deve piu' essere aspettato.
Lo cerco e lo rimuovo certo, ma in modo ?
Trascendiamo dallo scopo del BOT che ho gia' finito (il framework almeno).
Grazie e ciao.


 la ram di sistema e rentere necessario il riavvio?
Questo dipende da te e non da perl, sostanzialmente.
Se non introduci memory leak e se limiti la quantità di memoria
allocata, il programma avrà un'occupazione di memoria costante nel tempo
  (il motivo è spiegato nel seguito).
Se non prevedi limiti nella memoria allocata o se hai introdotto dei
memory leak, a lungo andare perl può generare un errore di "Out of
memory!"; ma è un fatto ovvio, non dipendente da Perl, che si 
verificherebbe ugualmente con qualsiasi altro linguaggio/interprete.
Il motivo per cui il tuo programma raggiungerà un picco nell'occupazione
di memoria e non schioderà più da lì (sempre che tu abbia adoperato le
necessarie limitazioni), è dovuto al fatto che la memoria deallocata
durante l'esecuzione di un processo, in generale *non* viene restituita
al sistema operativo, fino a quando il processo rimane in esecuzione.
"In generale" significa che dipende dal sistema operativo (e non da
perl) e che i sistemi operativi più diffusi si comportano tutti così: in
particolare Linux, inclusi i kernel 2.6, si comporta esattamente così (a
meno di patch di cui io non sono a conoscenza).
Per il resto il memory manager di perl ricicla internamente la memoria 
deallocata e, in generale, funziona benissimo (mi è capitato di scrivere 
un demone *monoprocesso* che è in esecuzione in produzione da oltre 6 
mesi senza alcun problema).
(L'unico caso che richiede un po' di attenzione per evitare memory leak, 
è quello delle strutture di dati circolari).
Se invece vuoi restituire al SO la memoria deallocata dal tuo programma 
mentre questo è ancora in esecuzione, allora ti tocca scrivere un 
programma multiprocesso, ovvero sostanzialmente un processo padre 
(sempre in esecuzione) che forka un nuovo processo figlio ad ogni 
connessione (il quale processo figlio ovviamente termina una volta 
gestita la connessione, restituendo così la memoria al SO).
Per quanto riguarda le tue altre domande, quello che ti serve sono
IO::MUltiplex e IO::Select.
Se, per scopi (auto)didattici vuoi lavorare a livello più basso, puoi 
dare un'occhiata al codice sorgente dei moduli predetti.
Ciao,
Emanuele.

 Emanuele.
Ciao
Roberto


 ma credo di non essere stato chiaro)
Mi permetto di insistere: dai un'occhiata ad IO::Multiplex, e 
probabilmente ci trovi tutto quello che ti serve. Se chiedi come fare le 
cose in maniera corretta e semplice in Perl, la strada è sempre quella: 
utilizzo a piene mani di CPAN (anche per studiare il codice).
Ciao,
Emanuele.
(*)
In realtà ci sarebbero alcune precisazioni da fare circa la gestione 
della memoria da parte di Linux/glibc, ma sarebbe troppo lungo.
Per farla breve, nel caso di memoria allocata con mmap() (che viene 
usata automaticamente da malloc() nel caso di allocazione di blocchi di 
memoria molto grossi) la memoria liberata viene restituita 
immediatamente al sistema operativo. Come già detto, questo non è però 
il comportamento "standard" di malloc, e avviene solo in casi molto 
particolari...

 Emanuele.
Ciao a tutti


 e' scritto come Richard Stevens insegna (sono suo fan).
Mi attacco al thread per tornare a segnalare un'iniziativa di
Perl.it che si prefigge lo scopo di documentare in maniera piu`
fruibile (in italiano, tanto per cominciare) tante perle che
esistono su CPAN e che talvolta e` difficile trovare se non 
tramite imbeccate o cose simili. 
Il progetto si chiama "Opliti", e prende spunto dal progetto
Phalanx [1]. Cito una mail di Aldo Calpini passata su 
mon...@perl.it
,
che spiegava e introduceva il progetto (ho solo svecchiato i link,
e tolto quelli non piu` attivi che comunque non servivano).
----------
cito dal poll di 
perl.it
:
 
  Un suggerimento: qualche pagina dedicata ai moduli per esempio quelli
  gli indispensabili, più usati, i più utili, i più scaricati...una cosa
  così che potrebbe servire come orientamente per i niubbi
 
sicuramente un'ottima idea, ma come realizzarla in pratica? non abbiamo
dati concreti sui moduli scaricati né tantomeno sull'utilizzo. possiamo
azzardare ipotesi sull'utilità o l'indispensabilità di qualche modulo,
ma sempre su base soggettiva. e non mi sembra opportuno disperdere le
nostre fin troppo poche energie per decidere cosa è indispensabile e
cosa no (cosa che rischierebbe tra l'altro di degenerare in sterili
flamewar del tipo "il mio modulo è più indispensabile del tuo").
 
però, però, c'è una base su cui secondo me potremmo considerarci
d'accordo: The Phalanx 100, i 100 moduli ritenuti più importanti
nell'ambito del progetto Phalanx.
(cfr 
http://qa.perl.org/phalanx/100/
 )
 
ecco, ora non ci sono più scuse. quello che ci serve, o miei opliti, è
una breve descrizione (da 5 a 50 righe, a occhio e croce) di ognuno di
quei 100 moduli, e poi un centurione benevolente che le metta in riga,
ci scriva un'introduzione degna di tale nome, ed ecco pronta la pagina
d'orientamento per i niubbi.
----------
Dopo un periodo di "stanca" il progetto si sta risvegliando, 
e siamo momentaneamente ospitato dal sito di Isogest, di cui
sfruttiamo il componente IGwiki:
 
http://www.isogest.org/cgi-bin/igwiki/opliti
Invito tutti a dare un'occhiata, e a rivolgersi a me, qui,
oppure su 
mon...@perl.it
, se volete chiarimenti oppure volete
cominciare a contribuire.
ciao e grazie,
S.
[1] 
http://qa.perl.org/phalanx/
-- 
Stefano Rodighiero      |  
http://larsen.perlmonk.org
mailto:
lar...@perl.it
   |  
http://www.perl.it

 Comunque non disturbo piu'. Mi accontento e ringrazio.
Nessun disturbo ;-)
Ciao,
Emanuele.