ich habe zwei while-Schleifen, welche ich gerne gleichzeitig laufen lassen würde. Unten der Code

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
MatLan
User
Beiträge: 9
Registriert: Freitag 14. Oktober 2022, 09:14

async def run(address):
async with BleakClient(address) as bleakclient:

def my_page_handler(data):
pass
print(data)
ret=client.publish("Python/MQTT",str(data))
#time.sleep(10)

#Verbindung mit Bleak Client aufbauen
print("Verbindungsaufbau mit Trainer")
await bleakclient.is_connected()
trainer = TacxTrainerControl(bleakclient)
#trainer.set_specific_trainer_data_page_handler(my_page_handler)
trainer.set_general_fe_data_page_handler(my_page_handler)
await trainer.enable_fec_notifications()
print("Verbunden mit Trainer")

#resistance = on_message
#Takt der Schleife in Sekunden
duration = 1

try:
#Dauerschleife
while 1:
#Methode zum setzen des Wiederstands
await trainer.set_basic_resistance(resistance)
print("set %s"%resistance)
await asyncio.sleep(duration)
break

except KeyboardInterrupt:
pass

await trainer.disable_fec_notifications()







# For in-place text-mode output


logging.basicConfig(level=logging.DEBUG)


# For in-place text-mode output
screen = TextScreen()
def text_format_8_ch(digits, volts):
digits_str = ", ".join([f"{i: 8d}" for i in digits])
volts_str = ", ".join([f"{i: 8.3f}" for i in volts])
text = (" AIN0, AIN1, Winkelsensor, AIN3, "
#" AIN4, AIN5, AIN6, AIN7\n"
f"{digits_str}\n\n"
"Values converted to volts:\n"
f"{volts_str}\n"
)
ret=client.publish("Lenkwinkel",str(volts_str))




return text

POTI = POS_AIN0 | NEG_AINCOM
LDR = POS_AIN1 | NEG_AINCOM
CH2 = POS_AIN2 | NEG_AINCOM
CH3 = POS_AIN3 | NEG_AINCOM
#CH4 = POS_AIN4 | NEG_AINCOM
#CH5 = POS_AIN5 | NEG_AINCOM
#CH6 = POS_AIN6 | NEG_AINCOM
#CH7 = POS_AIN7 | NEG_AINCOM

CH_SEQUENCE = POTI, LDR, CH2, CH3, #CH4, CH5, CH6, CH7

def loop_forever_measurements(ads):
while True:


raw_channels = ads.read_sequence(CH_SEQUENCE)

voltages = [i * ads.v_per_digit for i in raw_channels]
screen.put(text_format_8_ch(raw_channels, voltages))
screen.refresh()
time.sleep(5)

try:

with ADS1256() as ads:

ads.drate = DRATE_100

ads.cal_self()

loop_forever_measurements(ads)

except KeyboardInterrupt:
print("\nUser Exit.\n")



if __name__ == "__main__":

#Debugmeldungen aktivieren
os.environ["PYTHONASYNCIODEBUG"] = str(1)

#MAC Addresse von Trainer
device_address = "XX:XX:XX:XX:XX:XX"
#Starten der asynchronen Schleife mit Verbindung zu Trainer und MQTT Server
loop = asyncio.get_event_loop()
loop.run_until_complete(run(device_address))

"""
x = threading.Thread(target = run, args=(1,))
y = threading.Thread(target = loop_forever_measurements, args=(1,))
x.start()
y.start()
"""

######


Leider springt er nur in eine der beiden while-Schleifen. Ich habe es auch mit multiprocessing versucht und auch da kein Erfolg. Könnte mir jemand ein Beispiel geben wie ich beide while schleifen am besten mit Threads laufen lassen könnte?
Benutzeravatar
Kebap
User
Beiträge: 776
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Du kannst auch aus den zwei Schleifen eine Schleife machen, die beide Sachen nacheinander durchführt.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
__blackjack__
User
Beiträge: 14077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MatLan: Das kommt nicht am Compiler vorbei, weil syntaktisch nicht korrekt. In der Schleife in der `loop_forever_measurements()`-Funktionen kommen drei verschiedene Einrückungsebenen vor die sich um 2-3 Leerzeichen unterscheiden.

Dann fehlen jegliche Importe, da sind lauter undefinierte Namen im Quelltext.

Selbst mit Importen habe ich die starke Vermutung, dass da undefinierte Namen bleiben. In der `run`-Funktion ist beispielsweise `resistance` undefiniert. Da existiert zwar eine auskommentierte Zuweisung, allerdings ist das dort verwendete `on_message` ebenfalls nicht definiert. Und `client` auch nicht.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Noch schlimmer als das Hauptprogramm nicht in eine Funktion zu stecken, ist es das Hauptprogramm über das ganze Modul zwischen Definitionen von Funktionen zu verteilen/verstecken.

Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen, als Argument(e) übergeben. `loop_forever_measurements()` braucht beispielsweise `screen` als Argument. Und auch `client`, denn eine Funktion die von dort aufgerufen wird, benötigt `client`.

Konstanten definiert man am Anfang vom Modul, nach den importen, damit man die nicht suchen muss. Die MAC-Adresse ist wohl auch eher eine Konstante.

``str(1)`` ist eine umständliche Art ``"1"`` zu schreiben.

Wenn Strg+C zum abbrechen des Programms verwendet werden soll, dann muss das ``try`` zum ``except KeyboardInterrupt`` auch das gesamte Programm umfassen und nicht nur einen Teil. In der `run()`-Funktion hat das Konstrukt dann nichts mehr zu suchen — dort würde es dann ja nur zu einem Teilabbruch führen. Dafür müssen die Aufräumarbeiten nach einem Abbruch der Endlosschleife durch ein ``try``/``finally`` sichergestellt werden.

Eine Funktion die `text_format_8_ch()` heisst, aber nur 4 CH (was auch immer das sein soll) als Text formatiert, ist entweder falsch benannt, oder inhaltlich fehlerhaft.

`digits` heisst Ziffern, das sieht mir aber eher nach allgemeinen Zahlenwerten aus. Und auch `channels` in `raw_channels` sollte wohl eher `values` heissen.

`str.join()` kann man beliebige iterierbare Objekte geben, also auch Generatorausdrücke statt Listen.

Wenn man mit Rückgabewerten nichts macht, muss man die auch nicht an Namen binden. Schon gar nicht irgendwelche kryptischen Abkürzungen.

Python hat einen Datentyp (`bool`) mit den Werten `True` und `False` für Wahrheitswerte. Da sollte man keine Zahlen für missbrauchen.

Da alles in der `run()` darauf hindeutet, dass dort wirklich eine Schleife drin sein soll, muss das unbedingte ``break`` am Ende der ``while``-Schleife falsch sein, denn damit ist das ja gar keine Schleife mehr, sondern einfach nur Code der genau einmal linear abgearbeitet wird.

Den ``%``-Operator für Zeichenkettenformatierung zu verwenden ist etwas, das man in Python 2 schon nicht mehr gemacht hat. Es gibt die `format()`-Methode und f-Zeichenkettenliterale. Oder in diesem Fall einfach `print()` mit zwei Argumenten.

Man definiert keine Funktionen lokal zu anderen Funktionen wenn man nicht nutzt, dass das dann Closures sind. Wenn das eine normale Funktion ist, gehört die auf Modulebene, wo man sie testen kann.

`my` ist in 99,9% der Fälle ein vollkommen sinnloser Namenszusatz. Wenn es nicht auch ein `their` oder `our` gibt, gegen den sich das `my` abgrenzen könnte, bedeutet das einfach gar nichts.

``pass`` ist falsch wenn es nicht die einzige Anweisung ist, denn es ist ja genau dafür da etwas zu haben, wenn man sonst nichts in einen Block schreiben kann, weil da nichts gemacht werden muss.

`x` und `y` sind definitiv keine Namen für Threads.

Kommentare werden mit einem ``#`` eingeleitet. Zeichenketten sind kein Ersatz für Kommentare. ``#`` ist der einzige Kommentar den Python syntaktisch kennt.

Sofern die `loop_forever_measurements()`-Funktion nichts blockierendes enthält, könnte man daraus ja auch einfach eine asynchrone Funktion machen.

Zwischenstand (natürlich ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import asyncio
import logging
import os
from functools import partial

from somewhere import (
    ADS1256,
    DRATE_100,
    NEG_AINCOM,
    POS_AIN0,
    POS_AIN1,
    POS_AIN2,
    POS_AIN3,
    BleakClient,
    TacxTrainerControl,
    TextScreen,
)

#
# MAC Addresse von Trainer.
#
DEVICE_ADDRESS = "XX:XX:XX:XX:XX:XX"

POTI = POS_AIN0 | NEG_AINCOM
LDR = POS_AIN1 | NEG_AINCOM
CH2 = POS_AIN2 | NEG_AINCOM
CH3 = POS_AIN3 | NEG_AINCOM

CH_SEQUENCE = [POTI, LDR, CH2, CH3]

logging.basicConfig(level=logging.DEBUG)


def page_handler(client, data):
    print(data)
    client.publish("Python/MQTT", str(data))


async def run(address, client):
    async with BleakClient(address) as bleakclient:
        print("Verbindungsaufbau mit Trainer")
        await bleakclient.is_connected()
        trainer = TacxTrainerControl(bleakclient)
        trainer.set_general_fe_data_page_handler(partial(page_handler, client))
        await trainer.enable_fec_notifications()
        print("Verbunden mit Trainer")
        #
        # Takt der Schleife in Sekunden
        #
        duration = 1
        try:
            while True:
                await trainer.set_basic_resistance(resistance)
                print("set", resistance)
                await asyncio.sleep(duration)
        finally:
            await trainer.disable_fec_notifications()


def loop_forever_measurements(ads, screen, client):
    while True:
        raw_values = ads.read_sequence(CH_SEQUENCE)
        raw_values_text = ", ".join(f"{value: 8d}" for value in raw_values)
        volts_text = ", ".join(
            f"{value * ads.v_per_digit: 8.3f}" for value in raw_values
        )
        text = (
            "    AIN0,     AIN1,     Winkelsensor,     AIN3"
            f"{raw_values_text}\n\n"
            "Values converted to volts:\n"
            f"{volts_text}\n"
        )
        client.publish("Lenkwinkel", str(volts_text))
        screen.put(text)
        screen.refresh()
        asyncio.sleep(5)


async def main():
    os.environ["PYTHONASYNCIODEBUG"] = "1"

    client = ...

    try:
        screen = TextScreen()
        with ADS1256() as ads:
            ads.drate = DRATE_100
            ads.cal_self()
            #
            # Starten der asynchronen Schleife mit Verbindung zu Trainer und
            # MQTT Server.
            #
            measurements_taks = asyncio.create_task(
                loop_forever_measurements(ads, screen, client)
            )
            await run(DEVICE_ADDRESS, client)
            await measurements_taks

    except KeyboardInterrupt:
        print("\nUser Exit.\n")


if __name__ == "__main__":
    asyncio.run(main())
Geht wie gesagt nur falls `loop_forever_measurements()` nichts blockierendes enthält.

Und was komisch riecht ist dieser `client`. Selbst wenn das nicht `paho.mqtt` sein sollte, was nicht `async` ist, fehlen da ``await``\s, denn MQTT-Nachrichten verschicken ist definitiv was blockierendes was in `run()` und natürlich auch in eimem async `loop_forever_measurements()` Probleme machen kann.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
MatLan
User
Beiträge: 9
Registriert: Freitag 14. Oktober 2022, 09:14

Kebap hat geschrieben: Freitag 14. Oktober 2022, 14:01 Du kannst auch aus den zwei Schleifen eine Schleife machen, die beide Sachen nacheinander durchführt.
Vielen Dank das war :) ich habe da etwas zu umständlich gedacht :D
MatLan
User
Beiträge: 9
Registriert: Freitag 14. Oktober 2022, 09:14

__blackjack__ hat geschrieben: Freitag 14. Oktober 2022, 17:11 @MatLan: Das kommt nicht am Compiler vorbei, weil syntaktisch nicht korrekt. In der Schleife in der `loop_forever_measurements()`-Funktionen kommen drei verschiedene Einrückungsebenen vor die sich um 2-3 Leerzeichen unterscheiden.

Dann fehlen jegliche Importe, da sind lauter undefinierte Namen im Quelltext.

Selbst mit Importen habe ich die starke Vermutung, dass da undefinierte Namen bleiben. In der `run`-Funktion ist beispielsweise `resistance` undefiniert. Da existiert zwar eine auskommentierte Zuweisung, allerdings ist das dort verwendete `on_message` ebenfalls nicht definiert. Und `client` auch nicht.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Noch schlimmer als das Hauptprogramm nicht in eine Funktion zu stecken, ist es das Hauptprogramm über das ganze Modul zwischen Definitionen von Funktionen zu verteilen/verstecken.

Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen, als Argument(e) übergeben. `loop_forever_measurements()` braucht beispielsweise `screen` als Argument. Und auch `client`, denn eine Funktion die von dort aufgerufen wird, benötigt `client`.

Konstanten definiert man am Anfang vom Modul, nach den importen, damit man die nicht suchen muss. Die MAC-Adresse ist wohl auch eher eine Konstante.

``str(1)`` ist eine umständliche Art ``"1"`` zu schreiben.

Wenn Strg+C zum abbrechen des Programms verwendet werden soll, dann muss das ``try`` zum ``except KeyboardInterrupt`` auch das gesamte Programm umfassen und nicht nur einen Teil. In der `run()`-Funktion hat das Konstrukt dann nichts mehr zu suchen — dort würde es dann ja nur zu einem Teilabbruch führen. Dafür müssen die Aufräumarbeiten nach einem Abbruch der Endlosschleife durch ein ``try``/``finally`` sichergestellt werden.

Eine Funktion die `text_format_8_ch()` heisst, aber nur 4 CH (was auch immer das sein soll) als Text formatiert, ist entweder falsch benannt, oder inhaltlich fehlerhaft.

`digits` heisst Ziffern, das sieht mir aber eher nach allgemeinen Zahlenwerten aus. Und auch `channels` in `raw_channels` sollte wohl eher `values` heissen.

`str.join()` kann man beliebige iterierbare Objekte geben, also auch Generatorausdrücke statt Listen.

Wenn man mit Rückgabewerten nichts macht, muss man die auch nicht an Namen binden. Schon gar nicht irgendwelche kryptischen Abkürzungen.

Python hat einen Datentyp (`bool`) mit den Werten `True` und `False` für Wahrheitswerte. Da sollte man keine Zahlen für missbrauchen.

Da alles in der `run()` darauf hindeutet, dass dort wirklich eine Schleife drin sein soll, muss das unbedingte ``break`` am Ende der ``while``-Schleife falsch sein, denn damit ist das ja gar keine Schleife mehr, sondern einfach nur Code der genau einmal linear abgearbeitet wird.

Den ``%``-Operator für Zeichenkettenformatierung zu verwenden ist etwas, das man in Python 2 schon nicht mehr gemacht hat. Es gibt die `format()`-Methode und f-Zeichenkettenliterale. Oder in diesem Fall einfach `print()` mit zwei Argumenten.

Man definiert keine Funktionen lokal zu anderen Funktionen wenn man nicht nutzt, dass das dann Closures sind. Wenn das eine normale Funktion ist, gehört die auf Modulebene, wo man sie testen kann.

`my` ist in 99,9% der Fälle ein vollkommen sinnloser Namenszusatz. Wenn es nicht auch ein `their` oder `our` gibt, gegen den sich das `my` abgrenzen könnte, bedeutet das einfach gar nichts.

``pass`` ist falsch wenn es nicht die einzige Anweisung ist, denn es ist ja genau dafür da etwas zu haben, wenn man sonst nichts in einen Block schreiben kann, weil da nichts gemacht werden muss.

`x` und `y` sind definitiv keine Namen für Threads.

Kommentare werden mit einem ``#`` eingeleitet. Zeichenketten sind kein Ersatz für Kommentare. ``#`` ist der einzige Kommentar den Python syntaktisch kennt.

Sofern die `loop_forever_measurements()`-Funktion nichts blockierendes enthält, könnte man daraus ja auch einfach eine asynchrone Funktion machen.

Zwischenstand (natürlich ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import asyncio
import logging
import os
from functools import partial

from somewhere import (
    ADS1256,
    DRATE_100,
    NEG_AINCOM,
    POS_AIN0,
    POS_AIN1,
    POS_AIN2,
    POS_AIN3,
    BleakClient,
    TacxTrainerControl,
    TextScreen,
)

#
# MAC Addresse von Trainer.
#
DEVICE_ADDRESS = "XX:XX:XX:XX:XX:XX"

POTI = POS_AIN0 | NEG_AINCOM
LDR = POS_AIN1 | NEG_AINCOM
CH2 = POS_AIN2 | NEG_AINCOM
CH3 = POS_AIN3 | NEG_AINCOM

CH_SEQUENCE = [POTI, LDR, CH2, CH3]

logging.basicConfig(level=logging.DEBUG)


def page_handler(client, data):
    print(data)
    client.publish("Python/MQTT", str(data))


async def run(address, client):
    async with BleakClient(address) as bleakclient:
        print("Verbindungsaufbau mit Trainer")
        await bleakclient.is_connected()
        trainer = TacxTrainerControl(bleakclient)
        trainer.set_general_fe_data_page_handler(partial(page_handler, client))
        await trainer.enable_fec_notifications()
        print("Verbunden mit Trainer")
        #
        # Takt der Schleife in Sekunden
        #
        duration = 1
        try:
            while True:
                await trainer.set_basic_resistance(resistance)
                print("set", resistance)
                await asyncio.sleep(duration)
        finally:
            await trainer.disable_fec_notifications()


def loop_forever_measurements(ads, screen, client):
    while True:
        raw_values = ads.read_sequence(CH_SEQUENCE)
        raw_values_text = ", ".join(f"{value: 8d}" for value in raw_values)
        volts_text = ", ".join(
            f"{value * ads.v_per_digit: 8.3f}" for value in raw_values
        )
        text = (
            "    AIN0,     AIN1,     Winkelsensor,     AIN3"
            f"{raw_values_text}\n\n"
            "Values converted to volts:\n"
            f"{volts_text}\n"
        )
        client.publish("Lenkwinkel", str(volts_text))
        screen.put(text)
        screen.refresh()
        asyncio.sleep(5)


async def main():
    os.environ["PYTHONASYNCIODEBUG"] = "1"

    client = ...

    try:
        screen = TextScreen()
        with ADS1256() as ads:
            ads.drate = DRATE_100
            ads.cal_self()
            #
            # Starten der asynchronen Schleife mit Verbindung zu Trainer und
            # MQTT Server.
            #
            measurements_taks = asyncio.create_task(
                loop_forever_measurements(ads, screen, client)
            )
            await run(DEVICE_ADDRESS, client)
            await measurements_taks

    except KeyboardInterrupt:
        print("\nUser Exit.\n")


if __name__ == "__main__":
    asyncio.run(main())
Geht wie gesagt nur falls `loop_forever_measurements()` nichts blockierendes enthält.

Und was komisch riecht ist dieser `client`. Selbst wenn das nicht `paho.mqtt` sein sollte, was nicht `async` ist, fehlen da ``await``\s, denn MQTT-Nachrichten verschicken ist definitiv was blockierendes was in `run()` und natürlich auch in eimem async `loop_forever_measurements()` Probleme machen kann.


Vielen Dank ich habe einiges davon übernommen am Ende gings aber dann doch nur mit einer while--Schleife :)
Antworten