Forum >> Principianti >> Processi in parallelo

Pagina: 1

Salve a tutti,
sto scrivendo un programma che inizializza e/o utilizza diverse periferiche e quindi diversi processi tra loro indipendenti. In particolare:

- Inizializza un modulo seriale

- Inizializza e monitora la connessione da un dongle 3g (processo con "monitoring" continuo)

- Inizializza e acquisisce un ricevitore GPS (processo con acquisizione continua)

- Inizializza e attende o effettua chiamate VOIP.

Ogni periferica/processo utilizza una classe differente e metodi di inizializzazione, uso e chiusura dedicati.

E' chiaro che, trattandosi gli ultimi 3 di processi di attesa completamente eterogenei e provenienti da periferiche diverse, mettermi in attesa su uno significherebbe non far partire mai gli altri.

Ora, ho letto qualcosa sulle classi Threading e Multiprocessing.

Potrebbero fare al caso mio?O comunque, avete suggerimenti in merito?

Grazie infinite!


--- Ultima modifica di DarthUFO in data 2017-01-23 15:25:58 ---
Ciao caro e benvenuto.

Ti suggerisco di dare un'occhiata agli archivi della nostra mailinglist, ci sono diverse discussioni sull'argomento che ti potrebbero dare molte informazioni utili.

Ne ho estrapolate alcune, ma ce ne sono diverse altre che trattano l'argomento:
- Decorated Concurrency - Python multiprocessing made really really easy
- Aggiungere o distruggere una locked item in un dict mentre un'altro thread o asyncio lo legge/scrive per un'altra item?
- Thread e subprocess

Cya
Ciao Daniele,
grazie mille per i link.

Ho provato a leggere tutto, in particolare il primo link che ben prometteva, ma ahimè il mio livello da principiante rende tutto tremendamente più lento.
E anche San Google finora non mi ha aiutato granchè (forse per lo stesso motivo).

Nel timore di non essermi spiegato del tutto, quindi, giù ogni freno inibitore e cercherò di esplicitare meglio le mie necessità.

- Si tratta del "solito" Raspberry 3 che deve pilotare e gestire più dispositivi e relativi processi contemporaneamente.
- Questi dispositivi/processi non scambiano (al momento) dati tra loro.
- Le singole classi di ciascun dispositivo le ho già implementate e sembrano singolarmente funzionanti.
- facendo partire i singoli file *.py tutti in parallelo tutto sembra funzionare a dovere, la CPU ha un carico di circa il 30-40%.

L'unica cosa che questi dispositivi debbono "condividere" sono le fasi: inizializzazione, funzionamento a regime e chiusura. Per questo vorrei gestirli tutti tramite un solo file *.py "main" (passatemi la volgarità da non programmatore).

In comune hanno inoltre la connessione internet (spediscono dati verso un server) ottenuta tramite dongle 3G.

E per fare un esempio della necessità/problematica di avviarli in parallelo, ecco il primo intoppo.
La connessione sfrutta Wvdial, che è un dialer per PPP gestibile da riga di comando.
Per avviare la connessione, da Python richiamo tramite il modulo os il seguente comando:

import os
os.system('sudo wvdial 3gconnect').

A questo punto parte il log di wvdial.
Parte e continua fino alla chiusura della connessione o al kill di wvdial, bloccando di fatto tutte le istruzioni successive...

Se questo e altri processi di attesa e acquisizione funzionassero in maniera indipendente, ovviamente ciò non accadrebbe, e ciascuna acquisizione/log/monitoring avverrebbe in modo autonomo e verrebbe chiuso nella fase finale... Eventualmente "creperebbe" anche in modo autonomo non bloccando gli altri processi in corso.

Insomma, per questo tipo di attività che conviene fare?
Gestire più processi/thread o sono costretto a lanciare beceramente, grottescamente, pecorecciamente più *.py in parallelo?
Grazie e scusate la probabile banalità delle mie domande :embarrassed:


--- Ultima modifica di DarthUFO in data 2017-01-23 23:52:32 ---
In breve avrei bisogno di far funzionare funzioni "in parallelo" in in modo non bloccante.
Ad esempio, riducendo banalmente al caso di due funzioni che stampano il numero di ciclo in parallelo:


from threading import Thread
#import multiprocessing
import time


def ciclo_primo():
i=0
while i<100:
print("Ciclo Primo n ", i)
i += 1
time.sleep(1)


def ciclo_secondo():
i=0
while i<100:
print("Ciclo Secondo n ", i)
i += 1
time.sleep(1)


thread1 = Thread(target=ciclo_primo())
thread2 = Thread(target=ciclo_secondo())

try:
thread1.start()
thread2.start()
#thread1.join()
#thread2.join()

except(KeyboardInterrupt, SystemExit): #si esce quando viene premuto ctrl-c
print("Richiesta chiusura del programma")


Mi sarei aspettato che in parallelo (o quasi) venissero stampati messaggi del tipo:

('Ciclo Primo n ', 0)
('Ciclo Secondo n ', 0)

('Ciclo Primo n ', 1)
('Ciclo Secondo n ', 1)
...
('Ciclo Primo n ', 99)
('Ciclo Secondo n ', 99)


e via dicendo. Invece vengono stampati solo i messaggi relativi alla prima funzione fino alla conclusione del suo ciclo. Solo dopo vengono stampati quelli relativi alla seconda funzione/ciclo.
Cosa sto sbagliando?


--- Ultima modifica di DarthUFO in data 2017-01-24 15:34:43 ---
Ciao caro, usa il pulsante quando posti il codice, come sai la formattazione è importante, anzi vitale, in Python.

In questo momento sono in giro e col solo smartphone, non posso verificare il codice e/o proportene, ti faccio un po' di domande random.

Mi chiedo se essendo RPi la piattaforma, stai seguendo la strada migliore, viste le esigue risorse hardware?

Dici che hai verificato il funzionamento a regime, con cosa lo hai fatto, con (h)top o similari?

Come mai non fai un unico file? Magari con un'unica classe, dividendo le funzionalità in tre metodi distinti, visto che da quello che capisco non è troppo esoso il codice all'interno. Certo non otterrai le funzionalità in parallelo, ma se ti serve solo per far partire i dispositivi forse sprechi solo energie. Se poi ti serve per fare esperienza e studiare una cosa nuova, alzo le mani e ti do ragione.

Cya
Ciao Daniele e grazie sempre e comunque per il supporto. Ovviamente l'ultimo codice postato era di esempio...ho provato con il simbolo che mi hai consigliato, ma non mi cambia nulla (forse è il browser).

Allora, le 5 *.py che gestiscono altrettanti processi le ho testate con altrettante shell linux facendole partire singolarmente.

Questa sorta di "parallelizzazione cavernicola" ha comportato un utilizzo della cpu del 30% circa. E' stata monitorata con "Gestore Processi" di Raspbian (Debian) che è molto simile a "gestione attività" di windows.

Come ti dicevo, aldilà dell'aspetto puramente esperienziale, anche in un solo file il codice porterebbe agli stessi problemi.

Tutte le py, di per se, effettuano un lavoro continuo (log, streaming video, ecc) o attendono (ad esempio chiamate Voip).

Quindi la chiamata a una di queste funzioni bloccherebbe tutto il resto. Facevo l'esempio dell'avvio della connessione, che logga all'infinito fino al termine della connessione stessa.


In breve, dopo un'ulteriore giornata di tentativi anche con l'esempio di codice banale e non significativo di cui sopra, sono ancora stuccato al punto di partenza...


--- Ultima modifica di DarthUFO in data 2017-01-24 16:53:46 ---
Questo è sbagliato:
target=ciclo_primo()
Così provi ad assegnare a target il risultato della chiamata della funzione (che quindi viene eseguita dall'inizio alla fine). Il risultato ritornato è None, non parte alcun thread.

A target va assegnata la funzione.

Multiprocessing sarebbe meglio, il parallelismo viene gestito dal sistema operativo come se si lanciassero a mano i diversi programmi in modo indipendente, e su un sistema multicore i vari processi vengono fisicamente eseguiti da core diversi. Threading effettua invece un più lento switch software all'interno di un unico processo e i dati globali sono condivisi da tutti i thread (può essere un bene o un male a seconda del caso... il modo migliore per passare dati tra processi senza side effect dovuti alla concorrenza, è usare le queue).
*** Il codice va evidenziato con il simbolo di fianco ai colori per non perdere l'indentazione ***


Pagina: 1



Esegui il login per scrivere una risposta.