Topic: Threading Python 2.7  (Letto 2107 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 300
  • Punti reputazione: 0
    • Mostra profilo
Threading Python 2.7
« il: Gennaio 04, 2017, 01:52 »
Provengo dal PHP perciò sto faticando molto ad utilizzare e capire il concetto di threading.

[codice]#!/usr/bin/env python

"""
People's Poker Heads-Up SNG HUD

@Author: Tomas Bartoli <***@gmail.com>
@Date: 29/12/2016
@License: Copyright (C) 2016-2017

This software is not open source
"""

# Import general libraries used in the application
import os, sys, re, threading, time

# Import GUI libraries
import pygtk
pygtk.require('2.0')
import gtk

"""

"""
class HUDCore(object):

   __rootPath = None
   __dataPath = None
   __libPath  = None
   
   __config   = {}
   
   __dbOBj = None


   """
   
   """
   def __init__(self):
      self.__initEnvironment()
      self.__initDatabase()
      self.__initInterface()
   # End __init__
   
   """
    " Set environment data
    "
    " @method   private
    " @return void
   """
   def __initEnvironment(self):
      self.__rootPath = sys.path[0] + os.sep
      self.__dataPath = sys.path[0] + os.sep + 'data' + os.sep
      self.__libPath  = sys.path[0] + os.sep + 'libraries' + os.sep

      os.chdir(self.__libPath)
      sys.path.append(self.__libPath)
   # End __initEnvironment
   
   """
    " Connection and selection at the database
    "
    " @see      librariesdatabase.py
    " @method   private
    " @return   void
   """
   def __initDatabase(self):
      file = open(self.__dataPath + 'config.ini', 'r')
      while True:
         line = file.readline()
         if line == '':
            break
         search = re.findall('([A-Z]{4})s=s"(.*?)"', line)
         self.__config[search[0][0]] = search[0][1]

      file.close()

      import database
      self.__dbOBj = database
      
      self.__dbOBj.db(self.__config['HOST'],
            self.__config['USER'],
            self.__config['PASS'],
            self.__config['NAME'])
   # End __initDatabase
   
   """
    " Print GUI window 
   """
   def __initInterface(self):
      self.window = gtk.Window(type = gtk.WINDOW_TOPLEVEL)
 
      self.window.set_position(gtk.WIN_POS_CENTER)
      self.window.connect('delete_event', self.deleteEvent)
      self.window.connect('destroy', self.destroy)
      self.window.set_title('People's Poker Heads-Up SNG HUD')
      self.window.set_size_request(200, 50) 
      self.window.set_resizable(False)

      hbox = gtk.HBox(True, 10)
      hbox.set_border_width(10)
      self.window.add(hbox)
      hbox.show()

      self.BTNImport = gtk.Button('Start Import')
      hbox.pack_start(self.BTNImport, True, True, 0)
      self.BTNImport.connect('clicked', self.clickImport)
      self.BTNImport.show()
   # End __initInterface
   
   """
    " @see \__initInterface()
    "
    " @method   private
    "
    " @param   widget
    " @param   event
    " @param   data
    "
    " @return   bool   False
   """
   def deleteEvent(self, widget, event, data = None):
      return False
   # End deleteEvent
   
   """
    " @see \__initInterface()
    "
    " @method   private
    "
    " @param   widget
    " @param   data
    "
    " @return   bool   False
   """
   def destroy(self, widget, data = None):
      self.__dbOBj.close()
      self.window.destroy()
      gtk.main_quit()
   # End destroy

   """
   
   """
   def clickImport(self, widget, data = None):
      if self.BTNImport.get_label() == 'Start Import':
         self.BTNImport.set_label('Stop Import')
         
         var = threading.Thread(target=self.tryThread)
         var.setDaemon(True)
         var.start()
         
      else:
         self.BTNImport.set_label('Start Import')
   # End destroy
   
   def tryThread(self):
      i = 0
      while True:
         print str(i)
         i = i + 1
         time.sleep(5)

   
   """
   
   """
   def main(self): 
      self.window.show() 
      gtk.main()
      exit
   # End main
# End class HUDCore

if __name__== '__main__':
   init = HUDCore()
   init.main()
[/codice]

Se provate ad eseguire il codice ci sarà un bottone con scritto "Start Import", cliccandoci sopra vorrei venisse eseguita questa porzione di codice:
[codice]         var = threading.Thread(target=self.tryThread)
         var.setDaemon(True)
         var.start()
# [...]

   def tryThread(self):
      i = 0
      while True:
         print str(i)
         i = i + 1
         time.sleep(5)
[/codice]

e quindi cominciasse a stamparmi in loop dei numeri crescenti ogni 5 secondi, senza però condizionare il funzionamento del programma, non mi stupisce che non funziona, il ciclo viene avviato solo quando chiudo la GUI, perchè?

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 300
  • Punti reputazione: 0
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #1 il: Gennaio 04, 2017, 22:11 »
Grazie alla segnalazione di un utente di un noto forum di linux ho risolto, per correttezza posto il suo commento:

Citazione
telperion scrive:

Non è un problema di python
sono le gtk (e anche le altre lib grafiche) che sono un pain in the ass.

Con le gtk3 la soluzione è questa:
https://wiki.gnome.org/Projects/PyGObject/Threading

con le vecchie gtk2 (pygtk ) non saprei devi cercare

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #2 il: Gennaio 09, 2017, 01:07 »
Ma qualcuno usa ancora i thread in Python?

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 300
  • Punti reputazione: 0
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #3 il: Gennaio 09, 2017, 02:34 »
Ma qualcuno usa ancora i thread in Python?

Altrimenti cosa mi consigli?

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.151
  • Punti reputazione: 9
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #4 il: Gennaio 09, 2017, 10:26 »
Ma qualcuno usa ancora i thread in Python?
Specie con le gui direi di sì... spesso non è agevole incastrare il loop di un meccanismo asincrono nel main loop della gui (*)... d'altra parte invece è facilissimo sbattere un'operazione bloccante in un thread, perché il framework ti fornisce già le primitive thread-safe del caso... ci sono davvero pochissime regole da tenere a mente per usare i thread nelle gui, e per compiti normali e occasionali per cui in genere li si vuole usare è praticamente un no-brainer.


-- (*) almeno, parlo di quel che succedeva fino a ieri con asyncio, twisted... adesso bisognerebbe provare se cambia qualcosa con async e await ma francamente non ci ho ancora dedicato un pensiero.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #5 il: Gennaio 11, 2017, 09:39 »
Ma qualcuno usa ancora i thread in Python?
Specie con le gui direi di sì... spesso non è agevole incastrare il loop di un meccanismo asincrono nel main loop della gui (*)...

Io farei un discorso piu' semplice: "i thread sono pessimi (specie in Python)" + "le gui richiedono i thread" (qui ho un'obiezione) puo' anche avere come conclusioni:
1. non uso Python, oppure
2. non faccio GUI.

Come come? Gia'. Brutale. Pero' onestamente sensato. Anche perche' mentre (per dire) Java negli ultimi anni ha sviluppato una quantita' di roba attorno alle primitive di threading che risolvono (quando usate con un minimo di senso) la maggior parte dei problemi del modello (richiesta solo un briciolo di disciplina). Viceversa, Python e' rimasto dove stava tempo fa. In parte puo' essere utile multiprocessing.dummy, ma non siamo ancora a livello della concorrenza. Quindi ci troviamo con un affare che:

1. e' veramente complicato da gestire senza errori (a meno di non avere determinati strumenti che Python non offre)
2. funziona piuttosto malino nell'implementazione di Python

Beh, insomma... le questioni me le pongo. Cioe'... il giusto.

Citazione
d'altra parte invece è facilissimo sbattere un'operazione bloccante in un thread, perché il framework ti fornisce già le primitive thread-safe del caso... ci sono davvero pochissime regole da tenere a mente per usare i thread nelle gui, e per compiti normali e occasionali per cui in genere li si vuole usare è praticamente un no-brainer.

In primo luogo la regola sarebbe che qualunque cosa non sia FRP non voglio nemmeno vederla. Nota che, per inciso, FRP accomoda in modo piu' elegante *anche* la famosa computazione lenta.

Citazione
-- (*) almeno, parlo di quel che succedeva fino a ieri con asyncio, twisted... adesso bisognerebbe provare se cambia qualcosa con async e await ma francamente non ci ho ancora dedicato un pensiero.

No, non cambia davvero nulla. Deve detonare prima il GIL.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.151
  • Punti reputazione: 9
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #6 il: Gennaio 11, 2017, 17:13 »

> 1. non uso Python, oppure
> 2. non faccio GUI.

Sì beh, talmente tanta gente ha fatto talmente tante gui con Python, che non starei a farmi proprio questo scrupolo, ecco.
E se oggi sempre meno gente fa gui con Python, il motivo non è che che dicono "guarda, non sto più nella pelle di programmare una gui, è solo che sai, i thread in Python fanno così schifo...". Il motivo è che i gui framework per python sono fermi da secoli in stato di semi-abandonware, e le gui tutti voglio farle per il web o per le app mobili, dove guarda caso questi framework non arrivano.

Detto in altri termini, i thread sono un problema piuttosto tangenziale nella programmazione gui, e lo erano già negli anni d'oro, figurati oggi. Il motivo per cui chi programma gui usa i thread, a dirla tutta, è che i gui framework risalgono tutti a un'epoca piuttosto giurassica in cui i thread erano la cosa ovvia... quindi ci sono api, c'è documentazione, ci sono linee guida... E a maggior ragione oggi, non credo che qualcuno abbia veramente voglia di sbattersi a scrivere una libreria che integra asyncio in wxPython, per dire.

Cioè, siamo d'accordo che i thread in Python sono... tutto quello che sono. Ma quando programmi una gui, non ti capita praticamente mai di metterti nelle condizioni di rendertene conto. Lo scenario più classico in cui vuoi usare un thread in una gui, è per preparare un processo di stampa in background, o comporre un lungo report in pdf con reportlab senza che la gui vada in stallo per trenta secondi, per dire. Sono tutti casi in cui il thread non deve comunicare chissà che cosa con altri thread. Tutt'al più, quando ha finito posta in coda un feedback. In questi scenari, un thread è... buono abbastanza.




> In primo luogo la regola sarebbe che
> qualunque cosa non sia FRP non voglio nemmeno vederla.

Ecco, quando mi metto a discutere con te arrivano sempre questi momenti in cui mi chiedo se il tuo Python e il mio sono lo stesso linguaggio di programmazione.
Cosa posso rispondere, per levarmi dall'imbarazzo? Che sono d'accordo... per una definizione abbastanza elastica di FRP.
Cioè, se per FRP tu intendi un linguaggio che abbia delle primitive per fare FRP, beh allora però quel linguaggio non è Python (il *mio* Python per lo meno).
Se per FRP tu intendi un linguggio che ha per lo meno degli strumenti per fare FRP, allora di nuovo, io in Python non ne conosco, e se esistono sono abbastanza sicuro che nessuno ha fatto dei binding di questi strumenti per wxPython.
Cioè, prendi Haskell, per dire. Esiste Haskell. Ed esiste wxHaskell. Poi esiste Reactive-banana, che è un framework. E in mezzo tra wxHaskell e Reactive-banana esiste reactive-banana-wx, che è un binding che ti consente alla fine di fare FRP con le wx. Ora, tu sai di qualcosa di analogo nel mondo Python?


E quindi cosa resta? Se per FRP tu intendi un'architettura astratta o addirittura uno stile di programmazione, allora sì, sono d'accordo. Il punto è come implementare un approccio FRP in un framework OOP "vecchio stile", e in linguaggi che sono "nativamente OOP" come Python/C++.
Si parte dal principio che il "tempo" della FRP, in un gui framework "a eventi" è rappresentato dal mainloop. Si può tener traccia del cambiamento di stato dei vari componenti SOLO SE questi componenti sono disponibili a notificare il loro cambiamento presso il mainloop. E ci si rivolge al mainloop per schedulare le notifiche. Detto fuori dai denti, come è ovvio, observer pattern a manetta nel contesto di una sana progettazione MCV. Antiquariato anni '70, intendiamoci. Il particolare flavor di MCV nei gui framework consiste nel fatto che tu puoi (e devi) appoggiarti al mainloop per implementare i tuoi observer. Sopra questo strato C++, poi c'è Python che ti mette a disposizione degli strumenti in più (in wxPython, voglio dire). Ma il succo è questo.

Ora, che c'entra questo con i thread? Ma è questo il bello. Posto il fatto che comunque, nove su dieci, i thread secondari non hanno bisogno di interagire con la gui nel thread principale, il bello però è che, se proprio vuoi farlo, allora nessun problema: puoi usare lo stesso meccanismo di notifica SIA nel thread principale, SIA da un thread secondario verso il principale. Se dal thread secondario vuoi aggiornare lo stato di un componente della gui, semplicemente invii una notifica verso il mainloop. Poi quel componente riceve la notifica e si aggiorna. Il framework ti offre già delle primitive thread-safe per fare le notifiche. Non hai bisogno di pensare troppo. Ti basta inviare notifiche. Cioè quello che faresti comunque in una sana implementazione di observer (o pub/sub) appoggiata al mainloop del gui framework... che è poi la più vicina approssimazione a FRP che puoi fare in un mondo OOP - almeno credo, per quanto ne so.

Ecco perché tutto sommato non è poi così sciagurato usare i thread nei gui framework. Primo, perché in genere servono per lavori "autonomi". Secondo, perché non è difficile farli comunicare con la gui in modo sicuro, mantenendo anche una architettura sana.
Poi certo, d'accordo, Python, il GIL... ma questi sono aspetti che in genere non impattano molto la programmazione di gui.

Ci sono dei problemi, allora? Oh, certo. Se esci dal seminato di quello che il framework ti permette di fare, sei più o meno nella m* come per i "normali" thread Python. Comunicare tra un thread e l'altro? Comunicare dalla gui verso il thread secondario? Brrr... tutte cose possibili, ma già più problematiche. Eccetera.

Offline bebo

  • python erectus
  • ***
  • Post: 241
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re: Threading Python 2.7
« Risposta #7 il: Gennaio 11, 2017, 20:31 »
... Tutt'al più, quando ha finito posta in coda un feedback. In questi scenari, un thread è... buono abbastanza.

Mi intrometto nell'interessante discussione, anche se capisco poco questo gergo specifico..

Ho studiato concurrent programming, e dopo tutte le tecniche di programmazione parallela (semaphores, monitor, etc.) , alla fine si e' parlato brevemente che i thread sono lenti (creazione, distruzione), non scalano, e tutto il peggio di questo mondo, e che oggi si usano chiamate asincrone (ad esempio nei webserver, per gestire migliaia-milioni(?) di richieste).
Ora sto seguendo un corso di High Performance Computing, e stiamo usando OpenMP, che e' basato sui thread (a meno che non usi anche tecniche asincrone, ma non ne sono a conoscenza perche' devo ancora raccogliere insieme tutte le novita') ..

Questo era per arrivare alle mie domande: a parte GUI framework, quali sono i casi in cui "usare threading e' .. buono abbastanza", per citare ricpol? e quando non e' proprio il caso di usare chiamate asincrone?
Sto pensando ad esempio ad High Performance Computing, dove associamo ad ogni (o ad almeno un paio di) core del cluster un thread che fa una particolare operazione in parallelo.. questo e' uno di quei contesti in cui il threading puo' andare bene? come sarebbe invece lo scenario con delle chiamate asincrone? non ci sarebbe uno scambio di messaggi esagerato?

Perche' vengono "altamente sconsigliati" dappertutto i thread e ancora vengono insegnati in universita'? e non sono nemmeno in Italia al momento!
Vengono sconsigliati perche' la gente pensa che aumentando il numero di thread si crei un programma che lavora in parallelo e che quindi "va piu' veloce", facendosi inevitabilmente del male?

accetto volentieri anche link ad articoli chiarificatori ;-)

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #8 il: Gennaio 11, 2017, 20:50 »

> 1. non uso Python, oppure
> 2. non faccio GUI.

Sì beh, talmente tanta gente ha fatto talmente tante gui con Python, che non starei a farmi proprio questo scrupolo, ecco.
E se oggi sempre meno gente fa gui con Python, il motivo non è che che dicono "guarda, non sto più nella pelle di programmare una gui, è solo che sai, i thread in Python fanno così schifo...". Il motivo è che i gui framework per python sono fermi da secoli in stato di semi-abandonware, e le gui tutti voglio farle per il web o per le app mobili, dove guarda caso questi framework non arrivano.

Scusa, ma se 10 anni fa poteva essere una buona idea fare GUI con Python (riprova ne e' che "talmente tanta gente ha fatto talmente tante gui con Python... ora talmente tanta gente ha pure fatto talmente tante gui con VB6, il che non lo rende un buon prodotto). Comunque, assumiamo anche che *una volta* fosse una buona idea. Il fatto che tutto sia "semi-abandonware" (cosa che per inciso non mi torna, PySide sembrava abbastanza mantenuto) oggi potrebbe portarmi a prendere una diversa decisione.

E ancora una volta, se hai fatto gui con wx python per 10 anni, e' anche logico che in una valutazione consideri che conosci la minestra piuttosto bene e puoi controbilanciare tutti i limiti della faccenda con l'esperienza. Ma se stai *cominciando*, beh... potrebbe essere che non valga la pena buttarsi li.

Citazione
Detto in altri termini, i thread sono un problema piuttosto tangenziale nella programmazione gui, e lo erano già negli anni d'oro, figurati oggi. Il motivo per cui chi programma gui usa i thread, a dirla tutta, è che i gui framework risalgono tutti a un'epoca piuttosto giurassica in cui i thread erano la cosa ovvia... quindi ci sono api, c'è documentazione, ci sono linee guida... E a maggior ragione oggi, non credo che qualcuno abbia veramente voglia di sbattersi a scrivere una libreria che integra asyncio in wxPython, per dire.

Sono tangenziale fino ad un certo punto. Sono il modello di esecuzione della tua applicazione. Sono un modello *molto* complicato (da far funzionare... per scrivere un accrocchio che apparentemente funziona ma in effetti e' un castello di carte vanno benissimo). E sono una di quelle cose che tende a pervadere tutto. Di solito la gente che sa come programmarli sa anche come cercare di *non* programmarli (ovvero di usare astrazioni piu' sensate). Il problema e' che di solito ci si trova con una spaghettata dovuta al fatto che sono molto piu' complicati di quello che servono e che per tanta gente fanno "fico" (in effetti era una "cool thing" negli anni 90, sono passati venti anni). Con risultati disastrosi. E se c'e' speranza che in ambienti piu' evoluti le astrazioni siano sufficientemente diffuse ed evidenti che non sia difficile incontrarla (magari fin nei primi tutorial), in Python sono subito li. E sono dei falsi amici... perche' fanno venire voglia di usarne di piu' (invece che di usarne di meno).

Citazione
Cioè, siamo d'accordo che i thread in Python sono... tutto quello che sono. Ma quando programmi una gui, non ti capita praticamente mai di metterti nelle condizioni di rendertene conto. Lo scenario più classico in cui vuoi usare un thread in una gui, è per preparare un processo di stampa in background, o comporre un lungo report in pdf con reportlab senza che la gui vada in stallo per trenta secondi, per dire. Sono tutti casi in cui il thread non deve comunicare chissà che cosa con altri thread. Tutt'al più, quando ha finito posta in coda un feedback. In questi scenari, un thread è... buono abbastanza.

Magari inizi cosi'. Poi cominci a pensare che anche quell'altra operazione e' potenzialmente lenta e/o bloccante. E via un altro thread. E poi arriva quella che non e' puro output, ma bisogna anche prenderne il valore. E poi arrivano piu' thread che vogliono lavorare sullo stesso pezzo di stato. Etc etc etc.


Citazione
> In primo luogo la regola sarebbe che
> qualunque cosa non sia FRP non voglio nemmeno vederla.

Ecco, quando mi metto a discutere con te arrivano sempre questi momenti in cui mi chiedo se il tuo Python e il mio sono lo stesso linguaggio di programmazione.
Cosa posso rispondere, per levarmi dall'imbarazzo? Che sono d'accordo... per una definizione abbastanza elastica di FRP.
Cioè, se per FRP tu intendi un linguaggio che abbia delle primitive per fare FRP, beh allora però quel linguaggio non è Python (il *mio* Python per lo meno).
Se per FRP tu intendi un linguggio che ha per lo meno degli strumenti per fare FRP, allora di nuovo, io in Python non ne conosco, e se esistono sono abbastanza sicuro che nessuno ha fatto dei binding di questi strumenti per wxPython.
Cioè, prendi Haskell, per dire. Esiste Haskell. Ed esiste wxHaskell. Poi esiste Reactive-banana, che è un framework. E in mezzo tra wxHaskell e Reactive-banana esiste reactive-banana-wx, che è un binding che ti consente alla fine di fare FRP con le wx. Ora, tu sai di qualcosa di analogo nel mondo Python?

Per FRP intendo un modello di programmazione. Il punto non e' che il linguaggio *sia* funzionale o *funzionale puro*. Per esempio, a me non dispiace affatto sodium (in Java). Che e' veramente poco codice. Ma funziona bene.
Nel mondo Python c'e' praticamente solo RxPy che e' un port di Rx (che... diciamo che preferisco frp classico).

Citazione
E quindi cosa resta? Se per FRP tu intendi un'architettura astratta o addirittura uno stile di programmazione, allora sì, sono d'accordo. Il punto è come implementare un approccio FRP in un framework OOP "vecchio stile", e in linguaggi che sono "nativamente OOP" come Python/C++.
Si parte dal principio che il "tempo" della FRP, in un gui framework "a eventi" è rappresentato dal mainloop. Si può tener traccia del cambiamento di stato dei vari componenti SOLO SE questi componenti sono disponibili a notificare il loro cambiamento presso il mainloop. E ci si rivolge al mainloop per schedulare le notifiche. Detto fuori dai denti, come è ovvio, observer pattern a manetta nel contesto di una sana progettazione MCV. Antiquariato anni '70, intendiamoci. Il particolare flavor di MCV nei gui framework consiste nel fatto che tu puoi (e devi) appoggiarti al mainloop per implementare i tuoi observer. Sopra questo strato C++, poi c'è Python che ti mette a disposizione degli strumenti in più (in wxPython, voglio dire). Ma il succo è questo.

Non vedo nessun problema con il fatto che il linguaggio sia ad oggetti. Sodium per Java funziona in modo eccellente. Sodium c'e' anche per C++. Apparentemente c'e' qualche problemino di memoria (che mi verrebbe da imputare al fatto che magari gli autori non hanno C++ come primo linguaggio ma sono abituati alle modernita' di Java).

Citazione
Ora, che c'entra questo con i thread? Ma è questo il bello. Posto il fatto che comunque, nove su dieci, i thread secondari non hanno bisogno di interagire con la gui nel thread principale, il bello però è che, se proprio vuoi farlo, allora nessun problema: puoi usare lo stesso meccanismo di notifica SIA nel thread principale, SIA da un thread secondario verso il principale. Se dal thread secondario vuoi aggiornare lo stato di un componente della gui, semplicemente invii una notifica verso il mainloop. Poi quel componente riceve la notifica e si aggiorna. Il framework ti offre già delle primitive thread-safe per fare le notifiche. Non hai bisogno di pensare troppo. Ti basta inviare notifiche. Cioè quello che faresti comunque in una sana implementazione di observer (o pub/sub) appoggiata al mainloop del gui framework... che è poi la più vicina approssimazione a FRP che puoi fare in un mondo OOP - almeno credo, per quanto ne so.

Secondo me sei confuso su cosa sia FRP. O meglio... tu lo stai leggendo come:

Functional reactive programming

invece che come: "Functional Reactive Programming".

Poi quando metti insieme il modello con un sistema sensato di concorrenza (che e' gia' completamente integrato con il concetto di evento), vedi che anche fare roba in thread separati (specie quando ci ficca in mezzo primitive moderne) diventa estremamente piu' facile, robusto e godibile.

Citazione
Ecco perché tutto sommato non è poi così sciagurato usare i thread nei gui framework. Primo, perché in genere servono per lavori "autonomi". Secondo, perché non è difficile farli comunicare con la gui in modo sicuro, mantenendo anche una architettura sana.
Poi certo, d'accordo, Python, il GIL... ma questi sono aspetti che in genere non impattano molto la programmazione di gui.

Ci sono dei problemi, allora? Oh, certo. Se esci dal seminato di quello che il framework ti permette di fare, sei più o meno nella m* come per i "normali" thread Python. Comunicare tra un thread e l'altro? Comunicare dalla gui verso il thread secondario? Brrr... tutte cose possibili, ma già più problematiche. Eccetera.

Io credo che la maggior parte delle persone che fanno GUI + thread (non necessarimanete di mestiere, anzi) non solo non sanno come risolvere questi problemi: non sanno manco che esistono.
« Ultima modifica: Gennaio 11, 2017, 23:29 da riko »

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #9 il: Gennaio 12, 2017, 00:29 »
Ho studiato concurrent programming, e dopo tutte le tecniche di programmazione parallela (semaphores, monitor, etc.) ,

Ho studiato fecondazione assistita, e dopo tutte le tecniche di castrazione (ferro, castrazione chimica, ...) ,

Ehm... perdona la facezia. Il problema chiave e' che concurrency != parallelism.

https://blog.golang.org/concurrency-is-not-parallelism

Questo video va messo in ciclo continuo per tutte le notti per svariati mesi e tutti i giorni quando si va a lavoro/scuola e quando si ritorna.
Intanto perche' Pike quando parla lo si ascolta volentieri (anche se si dissente). In secondo luogo (quello specifico) perche' e' drammaticamente rilevante al problema.
Quindi... ora mi tocca misurarmi con Pike (confronto dal quale non posso che risultare sconfitto, purtroppo) e fare una breve premessa per tutti quelli che non andranno a vedersi il video.

A proposito... ho appena ricevuto un pacco con uno strumento che sperimentero' con coloro che non avranno visto suddetto video. Una preview...



Dicevo... scherzo. Guardatevi il video.


> Ora sto seguendo un corso di High Performance Computing, e stiamo usando OpenMP, che e' basato sui thread (a meno che non usi anche tecniche asincrone, ma non ne sono a conoscenza perche' devo ancora raccogliere insieme tutte le novita') ..

Concurrency != Parallelism. HPC e' principalmente una questione di parallelismo. Se pensi a quello che fai con OpenMP... il problema non e' essere asincrono (ovvero, non dovere aspettare). Il problema e' macinare quanti piu' dati possibile.

> Questo era per arrivare alle mie domande: a parte GUI framework, quali sono i casi in cui "usare threading e' .. buono abbastanza", per citare ricpol? e quando non e' proprio il caso di usare chiamate asincrone?

Ho paura di averti messo piu' confusione che altro.

Allora... io ho diversi problemi con i thread. Quando parlo di thread, in effetti, non parlo di thread, ma parlo di modello di programmazione sincrono a memoria condivisa. Questo e' il male.

Uso i thread tutti i giorni. Solo che li uso attraverso pool. E ci faccio programmazione asincrona. Ovvero... io faccio chiamate asincrone, sotto la JVM e il sistema operativo stanno facendo i giocolieri con i thread. Ma non e' davvero un problema mio. Oh... bisogna sempre stare attenti. Ma la faccenda diventa ragionevole. Sebbene formalmente la memoria sia condivisa, uso solo oggetti *immutabili* che quindi non hanno problemi ad essere condivisi. Se devo avere stato mutabile, lo proteggo molto bene dall'esterno e faccio in modo tale che non sia mai condiviso fra thread diversi (e se tutto questo fallisce, si rientra nel delirio di mutex e compagnia briscola).

Citazione
Sto pensando ad esempio ad High Performance Computing, dove associamo ad ogni (o ad almeno un paio di) core del cluster un thread che fa una particolare operazione in parallelo.. questo e' uno di quei contesti in cui il threading puo' andare bene? come sarebbe invece lo scenario con delle chiamate asincrone? non ci sarebbe uno scambio di messaggi esagerato?

Vedi.. il problema e' che "HPC" vuole dire tutto e niente. Allora, che dire... comunque diciamo di si. Ma il problema e' che usare tecniche di programmazione concorrente per fare programmazione non funziona particolarmente bene (come non funziona usare tecniche di programmazione parallela per fare programmazione concorrente).


Citazione
Perche' vengono "altamente sconsigliati" dappertutto i thread e ancora vengono insegnati in universita'? e non sono nemmeno in Italia al momento!

In universita' si insegna quello che i docenti disponibili conoscono (o credono di conoscere) e/o che pensano che sia importante.
E' una faccenda complicata che fatico a spiegare senza offendere (anche involontariamente) qualcuno.
Diciamo che e' molto caso per caso tutto quanto. Non aspettarti che ci sia una corrispondenza rigida fra "insegnato in universita' <-> utile", ma neppure che sia "insegnato in universita' <-> male".

Piu' una materia e' legata alla tecnologia e all'attualita' e piu' e' rischiosa. Ovviamente.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.151
  • Punti reputazione: 9
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #10 il: Gennaio 13, 2017, 22:22 »
riko
> "semi-abandonware" (cosa che per inciso non mi torna, PySide sembrava abbastanza mantenuto)

Sì, "mantenuto" è la parola chiave qui. Non c'è molta innovazione.

riko
> sei confuso su cosa sia FRP. O meglio... tu lo stai leggendo come:
> Functional reactive programming

Uhm, no, stavo solo argomentando... nei fatti mi sembra che frp sia una roba che si fa più spesso / esistono più soluzioni per linguaggi funzionali... Elm, Haskel... Ok c'è Sodium per Java/c++... ma non c'è per python... e men che meno per wxPython / gui varie.
Però, se accettiamo che il *principio* di frp possa essere implementato alla buona in termini OOP come un buon sistema di observer gestito da un main loop, allora questo è sicuramente possibile farlo nei gui framework. Le qt ce l'hanno più o meno nativo (signal/slot), per le wx è più complicato ma non tanto.

riko
> Magari inizi cosi'. Poi cominci a pensare che anche quell'altra operazione e' potenzialmente lenta e/o bloccante.
> E via un altro thread. E poi arriva quella che non e' puro output, ma bisogna anche prenderne il valore.
> E poi arrivano piu' thread che vogliono lavorare sullo stesso pezzo di stato. Etc etc etc.

Ah ma attenzione. Non sto dicendo che i thread sono una buona cosa. E non sto dicendo che i gui toolkit hanno un effetto magico per cui neutralizzano i problemi dei thread. I thread restano thread. E' sempre possibile spararsi sui piedi. Ma quel che voglio dire è che i gui toolkit ti suggeriscono gentilmente come puntare la pistola nella direzione non pericolosa.


bebo:
> Perche' vengono "altamente sconsigliati" dappertutto i thread
> accetto volentieri anche link ad articoli chiarificatori ;-)

Guarda, il discorso di Pike linkato da Riko non fa una grinza. Un altro link che mi resta sempre impigliato nei bookmark è questo https://glyph.twistedmatrix.com/2014/02/unyielding.html dell'uomo dietro a Twisted... è un po' vecchiotto, di quando asyncio ancora si chiamava tulip, ma è piuttosto didattico e mi piace sempre molto.

A quanto ne so, il più vecchio documento che sconsiglia i thread è questo http://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf. Forse Riko ne conosce di più vecchi, ma questo è stato seminale, è ancora oggi molto citato.
A me piace molto per una ragione che c'entra con questo discorso. Lui, al posto dei thread consiglia in sostanza di usare i callback gestiti da un mainloop. Ora, noi magari oggi possiamo storcere il naso, e comunque abbiamo delle opzioni in più. Ma non è un caso che proprio i gui toolkit, che sono più o meno coevi di quel documento, hanno abbracciato esattamente questa struttura: rigorosamente single-threaded, con un motore a eventi e callback gestiti da un mainloop.
All'epoca, questo fatto che i thread fossero un male era particolarmente evidente proprio nei gui toolkit. Se ci pensi, un gui toolkit sta esattamente al centro di una tempesta perfetta fatta di tre possibili sorgenti di guai:
- primo, deve gestire i segnali che vengono dall'alto, dall'utente: se tu scrivi in una casella di testo, il gui toolkit deve ridisegnare la casella a ogni nuova lettera che inserisci
- secondo, i segnali che vengono dal mezzo, da se stesso: tu magari non tocchi la casella di testo, ma mettiamo che invece apri un menu, e la tendina del menu copre la casella, e poi esci da menu e la casella è di nuovo visibile. Il gui toolkit deve sapere che deve ridisegnare la casella;
- terzo, deve gestire i segnali che gli vengono dal basso, dal sistema operativo: se l'utente trascina una finestra "estranea" sopra quella del tuo programma e copre temporaneamente la casella di testo, anche in quel caso il gui toolkit deve saperlo.
Ora, se provi a risolvere un problema del genere coi thread, sei morto: questo è proprio il genere di scenario in cui i thread combinano disastri. Di che scenario stiamo parlando? Come dice RIko...

riko
>  programmazione sincrono a memoria condivisa. Questo e' il male.

Proprio così. E infatti. Nessun gui toolkit usa una architettura a thread. Su questo non ci piove, e siamo d'accordo.
Ma proprio perché i gui toolkit hanno abbracciato una struttura diversa e sicura, rendono un pochino più agevole la vita a *te* se vuoi aggiungere un thread al mix per conto tuo. L'unica regola veramente fondamentale che devi ricordare è: mai toccare la gui "direttamente" da un thread secondario. Che cosa vuol dire "direttamente"? Che se hai una casella di testo e fai qualcosa come "casella.SetValue("hello")" da un thread secondario, la gui va in crash, non si scampa. Ma se invece di fare una cosa del genere, ti rivolgi gentilmente al mailoop e gli chiedi di schedulare il fatto che vuoi settare la casella di testo, allora sei di nuovo sul terreno solido. Basta rivolgersi sempre al mainloop. Le chiamate al mainloop sono sempre thread-safe.
Quindi, riassumendo, in un gui toolkit puoi fare queste cose coi thread in modo *sicuro*:
- usare un thread per un compito "locale" e "solitario", senza contatti con la gui: esempio, preparare un lavoro di stampa in background, senza bloccare la gui durante il calcolo.
- come sopra, ma aggiornare (alla fine, o periodicamete) un elemento della gui: esempio, un download lungo che periodicamente aggiorna un gauge con la percentuale di lavoro completata: nessun problema, basta non aggiornare il gauge direttamente ma chiedere al mainloop di schedulare.
- come sopra, ma scatenare la fantasia: più thread che aggiornano in modo concorrente lo stesso elemento della gui, e che magari scambiano anche dati tra di loro... Di nuovo, nessun problema: basta chiedere sempre al mainloop di fare da intermediario. OPPURE, puoi abbandonare il mainloop e usare le tue primitive di sincronizzazione, se sei sicuro... ma a questo punto il gui framework non ti sostiene più, e non venire a lamentarti se poi succedono disastri. Posto comunque sempre che, se vuoi interagire con la gui, allora l'intermediazione del mainloop è obbligatoria.

Questo è l'hello word dei thread in wxPython:
[codice]
import wx, threading, time

class Worker(threading.Thread):
    def __init__(self, target_box):
        threading.Thread.__init__(self)
        self._target_box = target_box

    def run(self):
        for i in range(10):
            # self._target_box.SetValue(str(i))    # questo non va bene!
            wx.CallAfter(self._target_box.SetValue, str(i))    # ma questo si'
            time.sleep(2)

class Main(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k)
        p = wx.Panel(self)
        self.box = wx.TextCtrl(p, pos=(10, 10))
        b = wx.Button(p, -1, 'start', pos=(10, 50))
        b.Bind(wx.EVT_BUTTON, self.on_b)

    def on_b(self, evt):
        worker = Worker(self.box)
        worker.start()

app = wx.App()
Main(None).Show()
app.MainLoop()
[/codice]

Qui la magia è tutta in wx.CallAfter, che implicitamente crea un evento e lo posta in coda nel mainloop. Questo è praticamente tutta la sintassi in più che bisogna sapere per usare un thread secondario che interferisce con la gui. Ma si può usare anche wx.CallAfter come sistema generale di comunicazione fra i thread, indipendentemente dalle azioni sulla gui, volendo.
Non è il rimedio di tutti i mali dei thread, ma è comunque un bel sollievo.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #11 il: Gennaio 15, 2017, 13:17 »
riko
> sei confuso su cosa sia FRP. O meglio... tu lo stai leggendo come:
> Functional reactive programming

Uhm, no, stavo solo argomentando... nei fatti mi sembra che frp sia una roba che si fa più spesso / esistono più soluzioni per linguaggi funzionali... Elm, Haskel... Ok c'è Sodium per Java/c++...

Non so dirti se "piu' spesso". A me verrebbe da dire che probabilmente e' andato in produzione piu' volte sodium che tutto haskell, per intenderci.

> ma non c'è per python... e men che meno per wxPython / gui varie.

Mi vengono in mente alcuni buoni motivi. Comunque non direi che la cosa e' fondamentale. Piu' che OOP vs. FP (e' piuttosto noto che un linguaggio imperativo ad oggetti moderno potrebbe consentire uno stile piuttosto funzionale -- Java di sicuro).
C'e' chi dice che sia una questione di static typing... in effetti ci sono tante comodita' che in Python si perdono. Ma verrebbe da dire che la faccenda e' piu' accidentale che sostanziale.
Insomma... se una cosa in Java si puo' fare, dubito che non si possa fare in Python (al limite sara' molto lenta). Ma in questo caso e' solo questione di librerie.

Perche' una roba del genere, in se e per se si scrive in boh... una settimana (se sai dove arrivare). Guarda l'implementazione di Sodium in Java. Che e' Java, se una cosa e' corta in Java...

https://github.com/SodiumFRP/sodium/tree/master/java/src/main/java/nz/sodium

E meta' della roba che e' li sono solo robe di FP (tuple, interfacce per lambda) che si sarebbero potute prendere da Java 1.8 (rinunciando ad essere compatibili con 1.7) o da Guava (prendendo la dipendenza per poche interfacce). Ma insomma... di quei 20 file la meta' hanno un'implementazione banale. La ciccia saranno boh... 2000 righe di Java.

Citazione
Però, se accettiamo che il *principio* di frp possa essere implementato alla buona in termini OOP come un buon sistema di observer gestito da un main loop, allora questo è sicuramente possibile farlo nei gui framework. Le qt ce l'hanno più o meno nativo (signal/slot), per le wx è più complicato ma non tanto.

Secondo me ti continua a sfuggire cosa sia FRP.


Citazione
riko
> Magari inizi cosi'. Poi cominci a pensare che anche quell'altra operazione e' potenzialmente lenta e/o bloccante.
> E via un altro thread. E poi arriva quella che non e' puro output, ma bisogna anche prenderne il valore.
> E poi arrivano piu' thread che vogliono lavorare sullo stesso pezzo di stato. Etc etc etc.

Ah ma attenzione. Non sto dicendo che i thread sono una buona cosa. E non sto dicendo che i gui toolkit hanno un effetto magico per cui neutralizzano i problemi dei thread. I thread restano thread. E' sempre possibile spararsi sui piedi. Ma quel che voglio dire è che i gui toolkit ti suggeriscono gentilmente come puntare la pistola nella direzione non pericolosa.

Do they? A me verrebbe da dire che la gente che fa UI ha spesso una presa meno solida su tutto il problema della concorrenza e alla fine dei conti di cose becere ne fanno tante quanto gli altri.
Il problema e' che di tutta la gente che scrive codice la vasta maggioranza dovrebbe fare altro nella vita. Poi business, cose, motivi e va bene cosi'.
Ma vedi, il fatto che nel 2016 si stia ancora a discutere dei thread, fa pensare che la conoscenza non percoli facilmente. O meglio, ci sono comunita' "avanzate" dove si diffonde molto rapidamente, ma prima che arrivi a tutti passano decenni (e tipicamente quello che arriva e' stato gia' sorpassato).



> Forse Riko ne conosce di più vecchi, ma questo è stato seminale, è ancora oggi molto citato.

No, essenzialmente e' uno dei piu' vecchi. Non me ne vengono in mente altri...

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.151
  • Punti reputazione: 9
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #12 il: Gennaio 26, 2017, 14:40 »
>> se accettiamo che il *principio* di frp
>> possa essere implementato alla buona in termini OOP
>> come un buon sistema di observer gestito da un main loop,

> Secondo me ti continua a sfuggire cosa sia FRP.

Mah, credo di averlo capito discretamente bene, ma come al solito non so se ho capito quello che tu stai pensando che io dovrei aver capito. Sicuramente capirei meglio se avessi un'ora da dedicare a questo video https://www.youtube.com/watch?v=j3Q32brCUAI (o comprare direttamente il libro), e spero che prima o poi. 

Quel che ho sempre capito è che frp *in astratto* riguarda la manipolazione di primitive ("Behavior" o "Cell" o come le vuoi chiamare) che rappresentano flussi di valori reali continui nel tempo. Fantastica idea.
Poi però se cerco di informarmi meglio e guardo le slide di quel video che non ho tempo adesso di guardare http://conal.net/talks/essence-and-origins-of-frp-lambdajam-2015.pdf vedo che l'autore si affanna subito a dire che frp NON è "updates and propagation". Ah beh, ok.
E se adesso ri-guardo l'intro di ReactiveX http://reactivex.io/intro.html vedo che gli autori si spendono molto a precisare che no, certo che no, Rx NON è frp perché Rx tratta valori discreti, e valori che vengono emessi (updates and propagation, appunto). Ma certo, poi tutti scambiano Rx per frp, accidenti a loro. C'è da chiedersi perché.

(Parentesi: questo mi porta a una curiosità parallela. Perché dici che Rx non ti piace? Io lo trovo interessante.)

Proseguiamo: siccome non ho tempo per comprare e leggere il libro, vedo però che c'è un discreto articolo introduttivo allegato al libro http://freecontent.manning.com/wp-content/uploads/2015/05/how-does-frp-work.pdf. E se leggo questo, vedo
- primo, che presenta un classico esempio di architettura che in OOP si risolverebbe a botte di observer,
- secondo, che tutta questa enfasi sui valori continui è immediatamente azzerata proprio all'inizio, quando dice che comunque ci vuole un meccanismo di framing, come a dire un clock, come a dire un main loop... uhm...
- terzo, che nell'ultima pagina presenta un codice Sodium che effettivamente è bello terso come un cielo di Tahiti, peccato solo che si tradisce nel commento: "Note the FRP code is really giving you something equivalent to a LISTENER INTERFACE for the outputs": ahh, ma ecco. E aggiunge subito "but the OOP for that would be too long"... e in effetti il frammento di c++ che mette per paragone ci fa una figura un po' misera, ma ho la sensazione che la stessa cosa scritta in Python invece sarebbe decisamente meglio.

E infine, grazie al tuo link, dò un'occhiata molto diagonale al codice di Sodium, ma mi sembra di capire che a lato pratico le cose fondamentali sono implementate a botte di observer... sbaglio?


Ora, la mia comprensione di frp è appunto, come scrivevo, che è un modello che può essere implementato in termini di OOP con degli observer... 
La prima volta che ho sentito "frp" (qualche anno fa? non ricordo) ho subito imparato l'analogia classica con le celle di un foglio di calcolo. E' l'analogia che imparano subito tutti, credo. E guarda caso, in termini OOP si implementa con degli observer.

Non so esattamente *cosa* mi sfugge, in effetti, di frp. Magari devo studiarmi elm per capirlo...

Ma torniamo a bomba. Questa lunga digressione su frp nasce da questo:
- io avevo detto che non è difficile appoggiandosi a un GUI framework scrivere un thread che comunica con il thread principale (tipicamente aggiornando un elemento della gui)
- tu avevi risposto che "per cominciare, se non è frp non lo voglio neanche vedere"
- io avevo risposto che, se accetti che frp sia implementabile a botte di observer e main loop, allora non è difficile neanche questo, appoggiandosi a un gui framework.

Ora, non so come faresti in pratica tu a implementare una gui (wxPython, diciamo, eh eh) con un'architettura frp. Io lo farei a botte di observer, appoggiandomi al main loop per schedulare gli update (da qualsiasi thread provengano). Cosa mi sfugge?

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Threading Python 2.7
« Risposta #13 il: Gennaio 28, 2017, 12:08 »
>> se accettiamo che il *principio* di frp
>> possa essere implementato alla buona in termini OOP
>> come un buon sistema di observer gestito da un main loop,

> Secondo me ti continua a sfuggire cosa sia FRP.

Mah, credo di averlo capito discretamente bene, ma come al solito non so se ho capito quello che tu stai pensando che io dovrei aver capito. Sicuramente capirei meglio se avessi un'ora da dedicare a questo video https://www.youtube.com/watch?v=j3Q32brCUAI (o comprare direttamente il libro), e spero che prima o poi. 

Quel che ho sempre capito è che frp *in astratto* riguarda la manipolazione di primitive ("Behavior" o "Cell" o come le vuoi chiamare) che rappresentano flussi di valori reali continui nel tempo. Fantastica idea.
Poi però se cerco di informarmi meglio e guardo le slide di quel video che non ho tempo adesso di guardare http://conal.net/talks/essence-and-origins-of-frp-lambdajam-2015.pdf vedo che l'autore si affanna subito a dire che frp NON è "updates and propagation". Ah beh, ok.
E se adesso ri-guardo l'intro di ReactiveX http://reactivex.io/intro.html vedo che gli autori si spendono molto a precisare che no, certo che no, Rx NON è frp perché Rx tratta valori discreti, e valori che vengono emessi (updates and propagation, appunto). Ma certo, poi tutti scambiano Rx per frp, accidenti a loro. C'è da chiedersi perché.

(Parentesi: questo mi porta a una curiosità parallela. Perché dici che Rx non ti piace? Io lo trovo interessante.)

Proseguiamo: siccome non ho tempo per comprare e leggere il libro, vedo però che c'è un discreto articolo introduttivo allegato al libro http://freecontent.manning.com/wp-content/uploads/2015/05/how-does-frp-work.pdf. E se leggo questo, vedo
- primo, che presenta un classico esempio di architettura che in OOP si risolverebbe a botte di observer,
- secondo, che tutta questa enfasi sui valori continui è immediatamente azzerata proprio all'inizio, quando dice che comunque ci vuole un meccanismo di framing, come a dire un clock, come a dire un main loop... uhm...
- terzo, che nell'ultima pagina presenta un codice Sodium che effettivamente è bello terso come un cielo di Tahiti, peccato solo che si tradisce nel commento: "Note the FRP code is really giving you something equivalent to a LISTENER INTERFACE for the outputs": ahh, ma ecco. E aggiunge subito "but the OOP for that would be too long"... e in effetti il frammento di c++ che mette per paragone ci fa una figura un po' misera, ma ho la sensazione che la stessa cosa scritta in Python invece sarebbe decisamente meglio.

E infine, grazie al tuo link, dò un'occhiata molto diagonale al codice di Sodium, ma mi sembra di capire che a lato pratico le cose fondamentali sono implementate a botte di observer... sbaglio?

Ora, la mia comprensione di frp è appunto, come scrivevo, che è un modello che può essere implementato in termini di OOP con degli observer... 
La prima volta che ho sentito "frp" (qualche anno fa? non ricordo) ho subito imparato l'analogia classica con le celle di un foglio di calcolo. E' l'analogia che imparano subito tutti, credo. E guarda caso, in termini OOP si implementa con degli observer.

Non so esattamente *cosa* mi sfugge, in effetti, di frp. Magari devo studiarmi elm per capirlo...

Ma torniamo a bomba. Questa lunga digressione su frp nasce da questo:
- io avevo detto che non è difficile appoggiandosi a un GUI framework scrivere un thread che comunica con il thread principale (tipicamente aggiornando un elemento della gui)
- tu avevi risposto che "per cominciare, se non è frp non lo voglio neanche vedere"
- io avevo risposto che, se accetti che frp sia implementabile a botte di observer e main loop, allora non è difficile neanche questo, appoggiandosi a un gui framework.

Ora, non so come faresti in pratica tu a implementare una gui (wxPython, diciamo, eh eh) con un'architettura frp. Io lo farei a botte di observer, appoggiandomi al main loop per schedulare gli update (da qualsiasi thread provengano). Cosa mi sfugge?


Se leggessi il libro che citi (quello di Manning), gli autori dicono fuori dai denti da dove viene FRP. FRP viene da anni di applicazioni fatte a botte di observer e listener, la cui complessita' ad un certo punto scappa di mano e diventano veramente dolorose da mantenere. Allora quello che succede e' che si comincia a mettere ordine nella foresta di listener, si comincia ad introdurre struttura, regole, vincoli. E piu' persone, partendo dallo stesso problema sono arrivate a cose molto vicine ad FRP.

Tornando a te... e' possibile scrivere frp sopra wxPython? Non vedo perche' non dovrebbe. Qualcuno dovrebbe pero' scrivere la libreria. E scrivere un engine FRP, anche se generalmente coinciso, e' molto delicato. Quindi preferirei che fosse li fatta e testata.

Quindi si, tipicament euna libreria FRP e' implementata internamente in termini di listener. Ma il punto e' appunto dare al programmatore un'astrazione piu' robusta e maneggevole.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.151
  • Punti reputazione: 9
    • Mostra profilo
Re: Threading Python 2.7
« Risposta #14 il: Gennaio 29, 2017, 13:15 »
Sì, grazie per il riassunto... è più o meno come pensavo.
Detto così a naso, non penso che sia un concetto molto attraente nel mondo delle "normali" applicazioni crud con gui (thread o no). La foresta dei listener non è praticamente mai così complicata da diventare ingovernabile, e i gui framework hanno sviluppato strategie abbastanza robuste per fare le cose a botte di observer/listener (vedi signal/slot nelle qt, o il sistema di eventi delle wx). Ovviamente, è sicuramente possible costruire un'applicazione gui "difficile" abbastanza da farti sentire la mancanza di qualcosa di più evoluto... Certo dovrei leggere il libro per vedere se fanno degli esempi delle architetture troppo complesse di cui erano insoddisfatti e per cui hanno sviluppato frp.