Topic: Controllo istanze di una applicazione, qualche consiglio?  (Letto 70 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline nuzzopippo

  • python neanderthalensis
  • ****
  • Post: 317
  • Punti reputazione: 0
    • Mostra profilo
I miei saluti

Sto raccogliendo "frammenti" di notizie per cercare di progettare una applicazione a scopo di esercizio.
Tale applicazione vorrebbe essere una chat point-to-point in lan locale. Particolare, ovvio, di tale applicazione è che deve avere un socket in ascolto su una determinata porta, che provveda ad accettare eventuali richieste di connessione e provveda ad instanziare un pool di oggetti dedicati alla comunicazione e gestione del relativo protocollo
 ... tale socket di ascolto lo prevedo attivabile/disattivabile dalla interfaccia utente e deve essere unico a livello di applicazione. Tale caratteristica di unicità "credo" di aversa risolta dopo un po' di ricerche (e con molte, zoppicanti, consultazioni del data-model di python) tramite una implementazione del pattern singleton, di seguito esposta in generico esempio, per eventuali interessati e magari per eventuali critiche, se opportune
>>> class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

>>> class Foo(metaclass=Singleton):
def __init__(self):
self._x = 0
def increment(self):
self._x +=1
def value(self):
return self._x


>>> foo_one = Foo()
>>> foo_two = Foo()
>>> print('foo_one ha valore %d, foo_two ha valore %d' % (foo_one.value(), foo_two.value()))
foo_one ha valore 0, foo_two ha valore 0
>>> foo_two.increment()
>>> print('foo_one ha valore %d, foo_two ha valore %d' % (foo_one.value(), foo_two.value()))
foo_one ha valore 1, foo_two ha valore 1
>>> foo_one == foo_two
True
>>>

Credo che un modello del genere dovrebbe andare bene circa l'unicità per l'oggetto di ascolto

... ma, qui mi pongo un altro problema, motivo di questo post, l'unicità del fantomatico oggetto è motivata, essenzialmente, dal lasciare libera la porta di comunicazione che prevedo di utilizzare a tal fine, la verifica che la porta sia occupata o meno è inibita dalla volontà di lasciare in mano all'utente se essere on-line o meno. Potrebbe anche tenere aperta l'applicazione e non voler essere in ascolto ma comunque vedere chi ascolta e comunicare (è così che lo voglio implementare).

Mi sorge, di conseguenza, la necessitò di verificare se è già aperta una istanza della applicazione, essendo possibilissimo lanciare diverse istanze contemporaneamente che non si "conoscono" tra loro ma che potrebbero, eventualmente, entrare in conflitto tentando di accedere alla stessa porta.
Allo stato, non avendo trovato niente di meglio, sarei indirizzato a controllare la faccenda tramite un file di lock scritto da qualche parte, cosa non difficile ma, data la più volte constatata presenza in python di "strumenti" da me non conosciuti, mi chiedo se è previsto qualcosa in merito, che magari non mi è riuscito di trovare, o delle metodologie "canoniche" per il controllo di istanze multiple per una applicazione python.

Grazie per l'attenzione.

Ciao :)

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.138
  • Punti reputazione: 9
    • Mostra profilo
Re:Controllo istanze di una applicazione, qualche consiglio?
« Risposta #1 il: Novembre 07, 2020, 12:05 »
Mah... sì, in effetti si tratta di due problemi separati... e mi chiedo se nel tuo caso non siano entrambi dei falsi problemi in realtà...

Da una parte c'è il "singleton pattern"... che serve a fare in modo che esista solo una istanza di una classe. Ora, come si sa il singleton è comodo da usare, ma spesso viene considerato una cattiva idea. Googlando in giro ("singleton considered harmful", per esempio...) si trovano diverse spiegazioni nel merito... Stringendo al massimo, si può usare il singleton per avere uno stato "globale" facilmente accessibile (e questo è l'uso sbagliato) oppure quando una classe ha delle funzionalità che sarebbe dannoso duplicare. Per esempio (faccio sempre gli stessi esempi...) wxPython fa attenzione che la wx.App possa essere istanziata solo una volta... e ci mancherebbe.

A lato pratico, comunque, c'è anche da dire difficilmente il singleton è utile nel codice di un programma "terminale" (specie se di piccole dimensioni). Puoi voler usare il singleton quando scrivi una libreria, per stare tranquillo che gli utenti della libreria poi non si spareranno nel piede in modo strano. Ma se stai scrivendo il tuo programma e vuoi essere certo di istanzare solo una volta una classe... boh... basta che la istanzi solo una volta, appunto. Nove volte su dieci basta e avanza, senza bisogno di ricorrere a check sofisticati.

Poi c'è il problema completamente separato di avere una sola istanza *del programma* in esecuzione. E questo però non lo puoi risolvere con il pattern singleton ovviamente... tu puoi avere una singola classe *per ciascuna istanza del programma*; ma poi ovviamente l'utente può avviare più istanze del programma contemporaneamente.
Questo è più difficile da risolvere, perché riguarda il sistema operativo e le mille cose che l'utente può fare con il suo computer. Che cosa succede se cade la corrente? Eccetera.
Ora, effettivamente acquisire un lock su un file "di test" è un modo usato... il problema è, talvolta, se il programma viene interrotto in modo prematuro... Un altro problema è fare questo in modo cross-piattaforma. In Linux esiste https://docs.python.org/3/library/fcntl.html#fcntl.flock, ma in windows no. Probabilmente, se hai cercato in giro, avrai visto questo https://github.com/pycontribs/tendo/blob/master/tendo/singleton.py che è appunto un esempio di implementazione cross-piattaforma di questa idea... Puoi prendere spunto.

A lato pratico, di nuovo, non sono sicuro però se valga la pena... da quello che capisco il tuo è un programma per l'utente finale, chiassoso ed evidente, con tanto di interfaccia grafica... davvero pensi che l'utente potrebbe avviarlo due volte?
E del resto... immagina di avere il tuo sistema di "singleton app" implementato. La seconda volta che l'utente avvia il tuo programma, che cosa succede? Ovviamente non può succedere "niente"... avrai come minimo bisogno di dirgli "guarda che c'è già un'istanza in esecuzione", e poi chiudi.
Invece, immagina di *non* avere la "singleton app"... quando l'utente avvia il programma per la seconda volta, questo prova a collegarsi alla porta e la trova già occupata. E quindi? Dirai all'utente "guarda che c'è già un'istanza in esecuzione", e poi chiudi. Non è la stessa cosa?
E se l'utente avvia l'istanza A, poi si disconnette (perché magari offri questa possibilità), poi avvia l'instanza B e si connette con quella... boh, che male c'è? Se poi cerca di riconnettersi con l'istanza A, verrà sbattuto fuori con un messaggio... di nuovo, mi sembra la stessa cosa.

Quindi non saprei se davvero è fondamentale implementare un sistema di questo tipo... in generale non lo vedo molto spesso in giro... piuttosto, si fa attenzione alle risorse "occupate" dal programma, e si reagisce se il programma trova la risorsa già occupata al suo avvio (tipo.. "questo file è già aperto da un'altra applicazione... sorry!"). Però vedi tu se effettivamente invece nel tuo caso una cosa del genere può aver senso.

Offline nuzzopippo

  • python neanderthalensis
  • ****
  • Post: 317
  • Punti reputazione: 0
    • Mostra profilo
Re:Controllo istanze di una applicazione, qualche consiglio?
« Risposta #2 il: Novembre 07, 2020, 18:45 »
Mah... sì, in effetti si tratta di due problemi separati... e mi chiedo se nel tuo caso non siano entrambi dei falsi problemi in realtà...
Ti ringrazio delle considerazioni fornite, materiale su pensare e senz'altro da approfondire, il design applicativo è certamente una mia grossa carenza.

Riguardo all'argomento "Singleton", durante le ricerche fatte avevo intuito che ci fosse in giro qualche questione non compresa, la ricerca suggerita da ampio materiale in risposta ... se ne trova anche cercando dopo aver tradotto in italiano :) , comunque, il livello delle motivazioni addotte e molto vicino al limite estremo del mio orizzonte attuale, spero di riuscire a comprendere di più in futuro.

Comunque, hai ragione, fondamentalmente è un falso problema, una definizione singleton non sarebbe necessaria, un controllo preliminare su una eventuale istanza dell'oggetto "di ascolto" sarebbe sufficiente ... fondamentalmente ho affrontato tale argomento "supponendo" che tale pattern vada "normalmente" applicato in caso un dato oggetto debba essere unico nella applicazione.
Devo dire, però, che è stata una ricerca molto interessante, ho trovato diversi metodi per realizzare un singleton (decoratori, definizione della classe, etc...) e lo sforzo di capirli, anche se magari non troppo riuscito, ha prodotto concetti interessanti (la strutturazione __call__, __new__, __init__, delle classi, p.e., balzata a nuova evidenza) ... particolarmente affascinante ho trovato l'argomento "metaclasse" (punto 3.3.3.1 della docs lincata nel mio 1° post), probabilmente non le userò mai o ben poco, però ...

passando al secondo argomento, grazie del link di tendo sarà interessante studiarmelo, flock l'avevo trovato ma essendo, appunto, per sistemi unix-like non ho voluto approfondirlo, lo farò se ne avrò bisogno per altro.

Riguardo se l'unicità della esecuzione di una applicazione sia o meno un falso problema ... sono incerto, ecco ... supponendo ambiente "normale" lo sarebbe certamente ma, forse per l'età avanzata di chi mi sta attorno, mi capita spesso di vedere  gente che apre contemporaneamente un numero spropositato di documenti, sessioni, etc, senza la minima consapevolezza di ciò che fanno (in genere vengono da me per "aiuto" in ufficio) ... tale consapevolezza mi fa propendere per l'idea di limitare ai limiti del possibile le cose "strane" che potrebbero fare ... che, so chattare in sola conversazione con una sessione ed in ascolto/dialogo con un'altra e poi chiedersi/mi perché mai degli interlocutori non possano essere aggiunti in una "stanza" di dialogo ristretta a pochi.

Comunque, grazie ancora del Tuo pensiero.