Jump to content

python3 wieder einmal ...


Recommended Posts

Geschrieben

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.

Geschrieben

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?

Geschrieben

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.

Geschrieben

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)

Geschrieben

... 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

Geschrieben

... 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

Geschrieben

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.

Geschrieben

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

Geschrieben

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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...