borg Geschrieben February 8, 2019 at 23:12 Geschrieben February 8, 2019 at 23:12 d.h. keine futures, sondern ** tasks ** die ge-gathered werden ? Ein task den du gatherest ist doch ein Future... Vielleicht hab ich meine Beispiele zu kompliziert gemacht, wie wäre es hiermit: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor import functools from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _executor = ThreadPoolExecutor(10) async def event_loop(loop): tf_async = functools.partial(loop.run_in_executor, _executor) ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) await tf_async(functools.partial(ipcon.connect, HOST, PORT)) task_temperature = tf_async(aq.get_temperature) task_humidity = tf_async(aq.get_humidity) result = await asyncio.gather(task_temperature, task_humidity) print('Temperature: {0}, Humidity: {1}'.format(*result)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) ipcon.connect wird asynchron mit Parameter aufgerufen und get_temperature und get_humidity werden asynchron "ge-gathered" und die Rückgabewerte ausgegeben. Zitieren
Malik Geschrieben February 9, 2019 at 13:24 Geschrieben February 9, 2019 at 13:24 So, du willst also was in Python 3.x machen weil du keine Zeit mehr mit Python 2.x vergeuden willst. Ganz deine eigene Sache. Dafür verlangst du aber von Tinkerforge, eine Python 3.x API zu erstellen. Wenn dir die Python-API nicht ausreicht, dann mach es doch wie "theo", der openhab-Bindings erstellt und der Community zur Verfügung stellt. Die Kenntnisse dafür scheinst du ja zu haben. Das mit dem Grundrecht hat mich etwas irritiert. Welche Hardware-Hersteller sind denn ebenfalls dieser Meinung? Zitieren
borg Geschrieben February 9, 2019 at 14:12 Geschrieben February 9, 2019 at 14:12 Dafür verlangst du aber von Tinkerforge, eine Python 3.x API zu erstellen. Nur um das klar zu stellen: Die Python-Bindings sind zu 100% kompatibel zu Python 3. Piwo möchte die Python-Bindings zusammen mit der Python 3 asyncio Library nutzen und da wir diese nicht intern verwenden benötigt es mehr Boilerplate Code um die Python-Bindings mit asyncio zu nutzen. Zitieren
Gast piwo Geschrieben February 9, 2019 at 21:39 Geschrieben February 9, 2019 at 21:39 mein gott - was ist daran so schlimm wenn man coroutinen einsetzen will (=kooperative nutzung EINES main-threads !!!!) durch intelligentess "loslassen" (nennt sich await) bei io-bound dingen bzw. hauptsächlichem nasenbohren ... mir ist schon klar, dass ich da AUCH mit dem multithreaded design der API leben muss. und mir ist klar, dass man da von heute auf morgen kein redesign vom zaun brechen kann ... ABER in worten *** ABER *** 1) die implementierung der API muss grundsätzlich eine (sinnvolle!) einbindung von kooperativem multiprocessing (COROUTINES) ERLAUBEN. und das in einer form, die das nicht ad-absurdum führt 2) man die offensichtlich nicht kompatibel implementierte API SCHONDEND einbinden können, d.h. dass dort nur die ALLERNOTWENDIGSTEN threads laufen, und dass auch die ZÄHMBAR sind. gibt genug nicht async-kompatible software, genauso wie es tonnen von nicht threadsafen libraries gibt. aber ich finde, die erbauer sollten sich da mal wirklich fundierte gedanken drüber machen. schnellschüsse aus der hüfte sind da nicht hilfreich. danke für das verständnis. bitte mal die natur coroutinen vs. threads behirnen. danke wp da ein feuerwerk mit thread-exekutoren abzufackeln ist NICHT das was in einem KOOPERATIVEN environment sinn macht 2) Zitieren
Gast piwo Geschrieben February 9, 2019 at 21:58 Geschrieben February 9, 2019 at 21:58 ... um das nochmals zu konkretisieren : ich will keine threads (wunschkonzert wider die API) ich will EINE MAIN LOOP für meine dinge, die ich über coroutinen "kooperativ" nutze. nicht mehr nicht weniger. wie ich das mache ist mein bier, aber ich muss eben leider mit der API leben, die da dagengearbeitet. also bitte von seiten der API mal nachdenken, wie man die ein möglichst wenigen hintergrudthreads ein ein coroutinen-umfeld einbinden kann. füttern von queues etc. also bitte nicht in den api-threads, sondern in welchen in der MAINLOOP = KOOPERTIV GENUTZTES (und einzig wichtiges) HAUPTPROGRAMM (ja. wie in der steinzeit *gggg*) ich habe die nase von threading voll. und python3 geht da in die ganz richtige richtung : statt dem abfeuern von unzähmbarer concurrency in threads, die man dann mit locks, notify und dem ganzen brimborium wieder mühsam sequentialisieren muss, rendezvous erzwingen, barriers setzen usw.: bullshit. es geht auch anders. danke den python3-entwicklern. und ich werde nur mehr so die dinge angehen. mir reichts .... lg wp Zitieren
Gast piwo Geschrieben February 9, 2019 at 22:30 Geschrieben February 9, 2019 at 22:30 ... letzte worte für heute : über concurrent.futures können wir uns unterhalten, sobald die ganze api in EINEM exekutor läuft ;-) ... oder tut sie es bereits ? lgw Zitieren
borg Geschrieben February 10, 2019 at 01:13 Geschrieben February 10, 2019 at 01:13 mein gott - was ist daran so schlimm wenn man coroutinen einsetzen will Nichts. 1) die implementierung der API muss grundsätzlich eine (sinnvolle!) einbindung von kooperativem multiprocessing (COROUTINES) ERLAUBEN. und das in einer form, die das nicht ad-absurdum führt 2) man die offensichtlich nicht kompatibel implementierte API SCHONDEND einbinden können, d.h. dass dort nur die ALLERNOTWENDIGSTEN threads laufen, und dass auch die ZÄHMBAR sind. Hier nochmal das Beispiel wie du die Python-Bindings asynchron nutzen kannst: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor import functools from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _executor = ThreadPoolExecutor(10) async def event_loop(loop): tf_async = functools.partial(loop.run_in_executor, _executor) ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) await tf_async(functools.partial(ipcon.connect, HOST, PORT)) task_temperature = tf_async(aq.get_temperature) task_humidity = tf_async(aq.get_humidity) result = await asyncio.gather(task_temperature, task_humidity) print('Temperature: {0}, Humidity: {1}'.format(*result)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) statt dem abfeuern von unzähmbarer concurrency in threads, die man dann mit locks, notify und dem ganzen brimborium wieder mühsam sequentialisieren muss, rendezvous erzwingen, barriers setzen usw.: Du musst dich in dem Beispiel um keine locks, notify, rendezvous oder barriers kümmern. Zitieren
Gast piwo Geschrieben February 10, 2019 at 14:19 Geschrieben February 10, 2019 at 14:19 okok. ... und wie sieht das letzte beispiel mit callbacks aus ? thresholds & debounce bzw. callback setzen adäquate einbindung des callbacks ... nach langen nachdenken wird es wohl nicht ohne EINE queue pro möglichem bricklet-callback laufen ... am besten sollten dort auch gleich die returns der getterfunktion landen, dann hätte das mal alles beisammen ... es wäre echt toll, wenn es eine referenz-implementierung gäbe, die dann in den docs ist und wo dann mehr leute diese verwenden & ev. eine verbesserung oder ein weiterspinnen möglich ist ... lgw Zitieren
borg Geschrieben February 10, 2019 at 23:35 Geschrieben February 10, 2019 at 23:35 Wenn du Callbacks nutzt und die Daten nicht direkt im Callback verarbeiten kannst, kommst du nicht darum herum entweder Queue oder vergleichbares zu nutzen oder nur den letzten Wert zu speichern. Das hat jetzt auch nichts mit asynchron vs prozedural zu tun, die Daten fallen nunmal komplett unabhängig von dem Mainloop an. Ich würde es wie folgt lösen: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _air_pressure_queue = asyncio.Queue() def cb_air_pressure(air_pressure, loop): asyncio.run_coroutine_threadsafe(_air_pressure_queue.put(air_pressure), loop) async def event_loop(loop): ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) ipcon.connect, HOST, PORT) aq.register_callback(aq.CALLBACK_AIR_PRESSURE, lambda x: cb_air_pressure(x, loop)) aq.set_air_pressure_callback_configuration(100, False, 'x', 0, 0) while True: air_pressure = await _air_pressure_queue.get() print('Air Pressure: {0}'.format(air_pressure)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) Wenn es darum geht Daten in einer Datenbank o.ä. zu speichern bietet es sich an eine Queue für alle Daten zu nehmen und den Typ des Datums mit zu speichern, z.B.: queue.put((TYPE_AIR_PRESSURE, air_pressure)) Da kannst du dann in deiner Mainloop eine Stelle haben an der du die Daten entgegen nimmst und ja nach Typ entsprechend bearbeitest und in der Datenbank speicherst Zitieren
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.