multiprocess beginner

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
ChristophS
User
Beiträge: 37
Registriert: Montag 7. August 2017, 12:52

Guten Abend

Mein Ziel ist es zwei Prozesse gleichzeitig laufen zu lassen. Dazu will multiprocess verwenden, scheitere aber schon beim ersten Beispiel:

Code: Alles auswählen

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
Pyton startet und im Terminal scheint etwas zu laufen, aber ausgegeben wird nichts. Mein Betriebssystem ist macOsSierra 10.12.6
In stackoverflow scheint man das Problem zu kennen, aber die vorgeschlagenen Lösungen scheinen für einfache Aufgaben nicht gemacht zu sein.

Christoph
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@ChristophS: um zwei Prozesse gleichzeitig laufen zu lassen, ist multiprocessing nicht wirklich das richtige. Wie versuchst Du denn Dein Skript zu starten?
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

also das Beispiel ist ja aus der Python Doku und funktioniert auch so, wie es soll (Ubuntu 16.04 mit P3.5). Ich sehe jetzt auch keinen Grund, warum das unter MacOS nicht laufen soll. Da das Beispiel trivial ist, sollte das Skript quasi sofort fertig sein.

Gruß, noisefloor
ChristophS
User
Beiträge: 37
Registriert: Montag 7. August 2017, 12:52

@Sirius3
Ich bin daran mich in Python einzuarbeiten und versuche an einfachen Beispielen zu verstehen.

Die von mir gestellte Aufgabe soll am Ende ein Window sein, bei dem ich zwei verschieden Prozesse starten kann.

Die Prozesse sind ganz einfache Zähler, die unterschiedliche Startwerte und Takte haben. Sie werden mit Buttons gestartet und aktuelle Werte werden in Entry's ausgegeben.
Window, Buttons und Entry's kann ich erstellen, auch der Zähler macht was er soll, bloss soll dieser im Hintergrund laufen und nicht alles blockieren bis er zu Ende gezählt hat, damit ich einen zweiten Zähler auch starten kann.

Es muss nicht multiprocess sein das ich verwende. Was ist ist besser geeignet?

@Noiseflor
Es ist das erste Beispiel aus der Doku und macht nicht was es soll.

Gruss
Christoph
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Es muss nicht multiprocess sein das ich verwende. Was ist ist besser geeignet?
GUI-Frameworks haben Methoden, die Funktionen periodisch ausführen können. Bei Tkinter ist das z.B. die `after()` Methode, Qt und GTK haben aber ähnlich Methoden. Bei GUI-Frameworks sollte man immer die Kontrolle mein Mainloop lassen und nicht noch mit anderen Threads oder Prozessen dazwischen fummeln (sofern man nicht ganz genau weiß, was man tut).
Es ist das erste Beispiel aus der Doku und macht nicht was es soll.
Wenn's bei dir nicht läuft und du auch keine Fehlermeldung bekommst, sondern der Terminal einfach nur blockiert, dann liegt das wohl eher an deinem Rechner / deiner Python-Installation als am Code. Der ist nämlich korrekt.

Gruß, noisefloor
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@ChristophS: solange Du nicht sagen kannst, was Du genau machst und was dabei genau passiert, kann man Dir nicht helfen. Bei mir und wahrscheinlich bei den meisten anderen läuft es.

multiprocessing ist definitiv für Deine Anwendung falsch. Einfache Zähler macht man mit einfachen Timern. Da bringen alle GUI-Rahmenwerke etwas passendes mit.
ChristophS
User
Beiträge: 37
Registriert: Montag 7. August 2017, 12:52

Erst mal Danke für die Antworten.

Dann muss ich wohl zurück auf Feld 1.

Ich will dass der Countdown mit dem STOP Button gestoppt werden kann. Geht aber nicht solange der Countdown läuft.

Christoph

Mein Code sieht so aus:

Code: Alles auswählen

from tkinter import*
import tkinter as tk
import time
import numpy as np
from Frames import *

def on_closing():    
    app.destroy()

def start():

    startButton1.config(state = DISABLED)
    stopButton1.config(state = NORMAL)

"""Hier ist mein Problem"""    
    countDown()

def stop():
    startButton1.config(state = NORMAL)
    stopButton1.config(state = DISABLED)
    fLEntry.delete(0,40)
    fLEntry.insert(0,str(startZahl))

def countDown():    
    startValue=fLEntry.get()
    countValue = int(startValue)

    while countValue > 0:
        countValue -= 1
        fLEntry.delete(0,40)
        fLEntry.insert(0,str(countValue))
        time.sleep(0.2)
        print (countValue)

startZahl = 100

app=Tk()
app.title('Einfacher down Zähler')
app.geometry('600x300+50+20')

left = app
left = Frame(app, height = 150 , width = 350, bd = 4, relief= FLAT, bg = "light grey")
left.place( x=20,y=30)
Frame1Label = tk.Label(left, text = "Runter zählen:", font=('Helvetica', 15, 'bold'), bg='light gray')
Frame1Label.place(x=8, y=5)

fLEntry = tk.Entry(left,
                      width=5,
                      textvariable = startZahl,
                      justify=RIGHT,
                      relief=FLAT)

fLEntry.config(bg = 'Light Cyan', bd =0)
fLEntry.place(x=109, y=32)

if fLEntry.get() == "":
    fLEntry.insert ( 0, startZahl)


fLEntryLabel = tk.Label(left, text = "Startzahl:", bg='light gray')
fLEntryLabel.place(x=8, y=33)

startButton1 = tk.Button(left, text = "Start", command=start, state= NORMAL, fg= "blue")
stopButton1 = tk.Button(left, text = "Stop", command=stop, state = DISABLED)
    
startButton1.place ( x= 180, y=32 )
stopButton1.place( x=240, y=32 )

line = Canvas (app, relief=SUNKEN, width=796, height=1, bg='black')
line.place(x=0, y= 25)
 
app.protocol(on_closing)
app.mainloop()
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Du Importierst tkinter sowohl als Sterncheimport als auch über den Namen tk. Ersters solltest Du nicht tun, weil Du damit unkontrolliert Namen in Deinen Namensraum holst. Genauso bei Frames, wobei ich nicht weiß was Frames ist und das gar nicht verwendet wird. numpy wird auch nicht verwendet.

Du benutzt globale Variablen, was Du schnell beseitigen solltest. Funktionen erhalten alle ihre Eingaben über Parameter. Bei GUI-Programmen kommt noch dazu, dass sie sehr statusbehaftet sind und man deshalb praktisch nicht daran vorbeikommt, eigene Klassen zu schreiben.

Was soll die 1 bei startButton1 und stopButton1? Die Schreibweise hält sich nicht an die Konvention, dass alle Variablen klein_mit_unterstrich geschrieben werden.

In Zeile 15 ist die Einrückung falsch. Strings sind auch kein Ersatz für Kommentare.

fLEntry ist ein ganz schlechter Variablenname, nicht nur wegen der Schreibweise, sondern auch, weil völlig unklar ist, was denn das f oder L zu bedeuten hat und Entry viel zu generisch ist. Ohne gute Variablenname ist Code nur schwer zu lesen und man muß raten, was er zu bedeuten hat.

Bei GUI-Programmierung dürfen Methoden nur sehr kurz laufen, weil sonst die GUI einfriert. countDown hat eine Schleife mit sleep. Das ist immer Falsch. Wie hier schon mehrfach angesprochen, gibt es bei TkInter die after-Methode, die eine Funktion nach einer bestimmten Zeit aufruft.

Alles ab Zeile 35 gehört auch in eine Funktion. Damit werden automatisch alle jetzt globalen Variablen zu lokalen und man kommt nicht in Versuchung, sie in anderen Funktionen "einfach so" zu verwenden.
Zeile 41 ist irgendwie nutzlos. Man sollte nicht place verwenden, sondern pack oder grid um Element zu platzieren. Das Fenster mag auf Deinem Rechner schön aussehen, bei einer anderen Auflösung oder in einem anderen Betriebssystem sieht es aber entweder nicht gut aus, oder ist gar nicht benutzbar.

Ungetestet:

Code: Alles auswählen

import tkinter as tk

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.counter = 100
        self.running = False
        self.title('Einfacher down Zähler')
        tk.Label(self, text="Runter zählen:").grid(0,0)
        self.display = tk.Label(self, text=self.counter)
        self.display.grid(1,0)
        self.start_button = tk.Button(self, text="Start", command=self.start, state=tk.NORMAL, fg= "blue")
        self.stop_button = tk.Button(self, text="Stop", command=self.stop, state=tk.DISABLED)
        self.start_button.grid(0,1)
        self.stop_button.grid(1,1)

    def start(self):
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.running = True
        self.after(100,self.count_down)

    def stop(self):
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.running = False
 
    def count_down(self):
        self.counter -= 1
        self.display.config(text=self.counter)   
        if self.counter > 0 and self.running:
            self.after(100, self.count_down)

def main():
    app = App()
    app.mainloop()

if __name__ == '__main__':
    main()
ChristophS
User
Beiträge: 37
Registriert: Montag 7. August 2017, 12:52

Ganz herzlichen Dank

Christoph
Antworten