Verbindung zur PostgreSQL Datenbank

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Ich habe mich mit ``async`` auseinandergesetzt, auch schon bevor Python das hatte. Das ist einer der Gründe warum ich der Meinung bin, dass das in Python eher ein Fremdkörper ist, weil ich das halt deutlich in besser in die Sprache und das Ökosystem integriert kenne. Und dann ist da noch `asyncio` als Modul das ich schlecht finde. Das geht IMHO aufgeräumter mit deutlich weniger Mechanismen die irgendwie alle das gleiche machen. Wo dann gleich der nächste Kritikpunkt anknüpft: warum ausgerechnet `asyncio` in der *Standard*bibliothek gelandet ist. Hat soweit ich weiss bei den Tornado-Leuten auch für ein bisschen Unmut gesorgt. Ich persönlich finde den schlankeren (und auch schnelleren) Ansatz von `curio` beispielsweise weniger verwirrend. Und soweit ich das beurteilen kann (ist schon ein bisschen her als ich mir ``async`` in Python näher angeschaut habe) deckt `curio` auch alles ab was `asyncio` kann.

Vom Autor von `curio`, David Beazley, gibt es auch ein ganz interessantes Video wo er live entwickelt und erklärt wie man so etwas implementiert von Generatoren, über Coroutinen, bis zu dem Punkt wo Python dann explizite Sprachunterstützung dafür bekommen hat.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@__blackjack__,

ich kenne die Videos von David Beazley. Einige haben mir sehr geholfen, das Konzept und den Ursprung von Async zu verstehen. Er hat in einem seiner Videos auch mal curio vorgestellt. Sein Ansatz, so wie ich es verstehe, war die Anwendung nah an der Verwendung von Threads zu orientieren und dabei die Nachteile von Threads zu vermeiden. Curio ist laut seiner Demonstration schneller aber eben auch (noch) experimentell, dazu nicht wirklich kompatibel mit anderen async frameworks.
Die async await Syntax versteckt ja eigentlich nur die alte Vorgehensweise mit @couroutine und yield.
Ich weiß nicht woher die Entscheidung dazu kam, aber oberflächlich sieht es so wie async-await in JavaScript aus.
Persönlich hatte ich mir zuerst Flask angeschaut und fand es ziemlich gut, bis ich anfing mit langlaufenden Hintergrundtasks zu experimentieren. Selbst in Miguel Grinbergs Flask Tutorial benutzt er dafür Celery.
Ich habe das zwar mal exemplarisch zum Laufen gebracht, es war für meine Zwecke aber zu viel extra Aufwand.
Von da habe ich es dann mit Node.js versucht. Da hat man dann alles komplett async und kann eigentlich gar nicht anders. Es scheint auf den ersten Blick auch alles gut ineinander zu greifen. Bei JavaScript - und da bin ich wohl nicht der einzige - hat man hinterher aber so viele verschachtelte Callbacks, dass man leicht den Überblickt verliert.
Als ich dann async in Python noch mal eine Chance gegeben hatte, fand ich es nach den ersten Hürden sogar viel besser.

Als dann auch FastApi komplett basierend auf ASGI kam, hab ich es damit versucht und ich konnte endlich Hintergrundtasks integrieren ohne großen Aufwand zu treiben.
zum Beispiel dieses kleine Experiment, wäre mir in Flask schwerer gefallen:

Code: Alles auswählen

import asyncio
import uvicorn
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse
from starlette.websockets import WebSocketDisconnect
from websockets.exceptions import ConnectionClosedOK

app = FastAPI()


PAGE = """
<!DOCTYPE html>
<html>
    <head>
        <title>Webscoket-Background-Task</title>
    </head>
    <body>
        <h1>Send Command</h1>
        <button onclick="sendMessage(event, 'Send')">Send</button>
        <ul id='messages'>
        </ul>

        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");

            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };

            function sendMessage(event, word) {
                ws.send(word)
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


async def execute_command(cmd):
    proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    return proc


async def shell_command(cmd):
    proc = await execute_command(cmd)

    while True:
        if not proc.stdout.at_eof():
            yield await proc.stdout.readline()
        elif not proc.stderr.at_eof():
            yield await proc.stderr.readline()
        else:
            break
    await proc.wait()
    yield f"return code: {proc.returncode}".encode()


@app.get("/")
async def get():
    return HTMLResponse(PAGE)


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    try:
        await websocket.accept()
        while True:
            await websocket.receive_text()
            async for line in shell_command("ping python.org"):
                await websocket.send_text(line.decode().strip())
    except (WebSocketDisconnect, ConnectionClosedOK):
        return

if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8000, ws="auto", log_level="debug")
Edit: Es ist erst ein Anfang, aber man kann schon jetzt mehrere parallele Websocket-Verbindungen aufbauen, ohne das ein Client blockieren würde. Die Hintergrundtasks werden natürlich auch parallel ausgeführt. Selbst wenn man mehrmals auf Send clickt, geht die Information nicht verloren und nichts geht durcheinander.

Python ist schon ziemlich alt. Viele der heutigen Anforderungen waren damals wohl noch nicht abzusehen. Ob man es hätte besser machen können kann ich nicht beurteilen. In welcher Sprache ist async denn deiner Meinung nach besser integriert?
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Was meinst Du mit `curio` ist nicht wirklich kompatibel zu anderen ``async``-Rahmenwerken? Andere ``async``-Rahmenwerke sind nicht kompatibel mit anderen ``async``-Rahmenwerken, darum sind es ja *andere* Rahmenwerke als `asyncio`. Das ist ja gerade die Kritik daran, das `asyncio` einfach so in die Standardbibliothek gepackt wurde und damit faktisch einen Vorteil gegenüber anderen hat, weil alle gezwungen sind entweder mit `asyncio` kompatibel zu sein, oder ihr eigenes Ökosystem aufzubauen das parallel zu dem existiert was in der Standardbibliothek ist. An der Stelle wäre es IMHO deutlich besser gewesen etwas kleineres, weniger komplexes und umfangreiches in die Standardbibliothek aufzunehmen, auf dem andere Rahmenwerke dann aufbauen können. Man kann beispielsweise die `asyncio`-Bibliothek auf `curio` aufbauen. Umgekehrt wäre das eher eine Rück- und Umbauaktion.

Du hast da jetzt als Beispiel Websockets gewählt — klar geht das asynchron ”einfacher”, weil es ohne gar nicht geht, es sei denn man programmiert es komplett selbst. Ich habe da jedenfalls auf die schnelle keine Bibliothek gefunden.

Asynchrone Programmierung ist hauptsächlich in den Sprachen besser integriert, wo das von Anfang an zur Implementierung im Kern dazu gehört. Natürlich habe ich da als erstes JavaScript (und Sprachen die man zu JavaScript kompilieren kann) im Kopf. Übrigens nicht unwesentlich davon angetrieben *GUI*-Ereignisse zu verarbeiten und auszulösen. Direkt die Netzwerkkommunikation in JavaScript zu machen kam ja erst *deutlich* später dazu. Sowohl im Browser als auch bei Node.js ist die Eventloop in der Sprachimplementierung gleich drin, und nicht als Bibliothek die man optional importieren und nutzen kann oder auch nicht.

Io würde mir da auch noch einfallen was von Anfang an asynchrone Methodenaufrufe und transparente Futures hat. Das heisst da gibt es kein explizites „await“, das ist implizit wenn man einen Wert benutzen will, der noch nicht fertig berechnet ist. Und auch Methoden muss man nicht als „async“ kennzeichnen, man kann jede Methode asynchron aufrufen wenn man das möchte. Das nenne ich mal eine Integration in die Sprache. 🙂
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@__blackjack__,
Genauer gesagt, curio ist nicht kompatibel mit asyncio. So jedenfalls die Erklärung auf der curio github Seite.
Ich sehe curio als ein Demo Projekt von David Beazley. Es scheint mir, es war auch nie das Ziel, daraus mehr als ein Experiment zu machen. Er ist ein Python-Coach und curio ist sein Anschauungsobjekt, wenn auch wie es zumindest scheint, ein sehr gutes.
Das ist ja gerade die Kritik daran, das `asyncio` einfach so in die Standardbibliothek gepackt wurde und damit faktisch einen Vorteil gegenüber anderen hat, weil alle gezwungen sind entweder mit `asyncio` kompatibel zu sein, oder ihr eigenes Ökosystem aufzubauen das parallel zu dem existiert was in der Standardbibliothek ist.
Ich wüßte nicht warum das ein Problem ist. Die anderen sind nicht gezwungen mit asyncio kompatibel zu sein. Obwohl sie das wohl anstreben.
Laut Dokumentation von Tornado kann man mittlerweile Tornado-Code mit asyncio - Code kombinieren.
Ich wüsste allerdings nicht wozu. Beide Frameworks sind gut mit Funktionen ausgestattet.
Als Anwender hat man doch die Freiheit aus mehreren Angeboten zu wählen.
Man könnte sonst ja auch das gleiche Argument gegen Tkinter bringen. Eine Kompatibilität zwischen GUI-Frameworks ist aber gar nicht nötig, da alle in sich abgeschlossen sind.
Es ist ja auch nicht so das Tkinter jetzt irgendeinen Vorteil hätte. Andere Frameworks, haben sich sogar weiterentwickelt und haben Tkinter zurückgelassen.
Wenn jemand der Meinung ist, es müsste ein besseres async Framework als asyncio geben, kann das doch ohne Probleme neben asyncio existieren und sogar besser sein.

Bisher scheint das aber niemand wirklich anzustreben.
Wenn ich mal die beiden Beipiele für einen Mini-TCP-Server vergleiche, finde ich asyncio wesentlich sauberer.
https://www.tornadoweb.org/en/stable/io ... oop.IOLoop
https://docs.python.org/3/library/async ... ng-streams

Und ich denke deswegen entsteht ein Ecosystem um asyncio. Das kann doch nicht daran liegen, dass da irgend ein Zwang besteht, sondern daran, dass es klare Vorteile gibt.

Ich habe in meinem Beispiel Websockets gewählt, weil das das Problem war, dass ich lösen wollte. Asyncio war die Lösung zu meinem Problem. Für andere Probleme gibt es andere Lösungen. Es ist kein Anspruch auf eine Universallösung für jede Art von "paralleler" Programmierung.

Den einzigen Vorteil, den ich bei JavaScript sehe, ist der, dass man sich nicht um die Eventloop kümmern muss. Das heißt aber nicht, dass man da munter synchronen Code mit asynchronem Code mischen kann.
Wenn man sich einmal in einer Kette von Promises befindet, kommt man nicht mehr heraus. Ein Promise hat keinen Rückgabewert sondern ein Callback. In Python kann ich wenigstens aus eine Coroutine noch einen Rückgabewert bekommen und damit weiter arbeiten. Also von daher bin ich eigentlich froh, dass async eben nicht so tief integriert ist. Das würde gar nicht möglich sein und Python wäre dann auch eine andere Sprache.

Fazit, ich sehe das Problem nicht. Ich habe auch sonst nicht viel Negatives zu asyncio oder zu asynchronen Frameworks im allgemeinen gehört. Daher ja meine Verwunderung.
Ich kann verstehen, dass man sich nicht weiter damit beschäftigt, wenn man kein Interesse oder Nutzen sieht, aber zum Glück kann man sich ja dazu entscheiden asyncio nicht zu verwenden und das Leben geht synchron weiter.
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Woraus leitest Du ab, dass `curio` nicht ernst gemeint sondern nur ein Experiment ist?

Gleich er erste Punkt in der FAQ in der README ist folgender:
Q: What is the point of the Curio project?

A: Curio is async programming, reimagined as something smaller, faster, and easier to reason about. It is meant to be both educational and practical.
Man kann aber als Anwender nicht so leicht aus mehreren Angeboten wählen wenn eines sehr stark dadurch hervorgehoben wird, dass es in der Standardbibliothek vorhanden ist. Es wird aus der Python-Dokumentation nicht so deutlich das ``async``/``await`` nicht nur mit `asyncio` in der Standardbibliothek funktionieren, sondern dass es Alternativen gibt, beziehungsweise geben könnte. Wie immer wenn es neue Sprachfeatures gibt, tauchen tausende von Blog-Beiträgen und Youtube-Videos dazu auf die das rudimentär erklären, die natürlich alle `asyncio` verwenden. Im Package-Index gibt es viele Packages die auf `asyncio` aufbauen – weil das in der Standardbibliothek ist und damit einfach einen „ist schon bei jedem vorhanden“-Bonus hat.

Und ja, das Argument kann man tatsächlich auch gegen `tkinter` vorbringen. Es ist auch nicht so wirklich vergleichbar, denn das GUI-Rahmenwerke in sich geschlossen sind, liegt auch daran, dass man auf den verschiedenen Plattformen auch GUI-Schnittstellen hat die es gar nicht mögen wenn sie versucht werden von verschiedenen GUI-Rahmenwerken gleichzeitig benutzt zu werden. Zudem gibt es Kombinationen die erzwingen, dass die GUI vom Hauptthread bedient wird. Das ist alles an sich schon mal eine Ecke komplexer als eine simple Eventloop die man von Grund auf selbst aufbauen kann.

Bei GUI-Rahmenwerken gibt es auch mehr Wettbewerb weil die Konkurrenten von ein paar Faktoren abhängen an denen man nicht wirklich umhin kommt ein anderes zu wählen. Bei Tk beispielsweise wenn man eine moderne GUI haben will, mit den Widgets und Teilrahmenwerken, die man heute eigentlich erwartet. Und Qt schränkt einen bei der Lizenz ein. Gtk ist nicht unter allen Plattformen besonders geeignet. Touch-Unterstützung ist bei Kivy wohl am besten. Die haben alle ihre Besonderheiten.

`tkinter` hat keine eigene Syntax in Python. Das macht `asyncio` auch anders, dass es zu Syntax gehört.

In der Praxis ist zumindest unter Linux `tkinter` auch mehr oder weniger optional, weil die meisten Distributionen das in ein eigenes Package auslagern, damit man sich auf Servern nicht alle möglichen GUI-Abhängigkeiten einfängt, die man da überhaupt nicht braucht/haben will.

Du gehst einfach davon aus das `asyncio` einen Vorteil gegenüber anderen Bibliotheken haben muss, beziehungsweise die deswegen nicht bestehen. Und siehst das nicht-bestehen als Beweis dafür. Aber genau diese Sicht führt ja dazu, dass es keine anderen Bibliotheken gibt, beziehungsweise die vorhandenen nicht so verbreitet sind, oder sich *gezwungen* sehen zu `asyncio` kompatibel zu sein. Da hast Du Deinen Zwang.

Über die Jahrzehnte gab's halt auch immer wieder Leute denen man Gtk oder Qt empfohlen hat, die sich dagegen gesträubt haben, weil es doch einen Grund geben muss das `tkinter` in der Standardbibliothek ist. Das gleiche mit Leuten die das hässliche `xml.minidom` verwendet haben bevor die `ElementTree`-API endlich in die Standardbibliothek aufgenommen wurde. Das etwas in der Standardbibliothek ist, verzerrt einfach das Bild, egal wie furchtbar die API in der Standardbibliothek gegenüber einem externen Package ist.

Die Debatte, dass die Standardbibliothek zu viel und zu komlexes enthält, kommt auch ab und zu auf. Also ob man überhaupt ein GUI-Rahmenwerk in der Standardbibliothek haben sollte. Oder zwei XML-Parser-APIs. Wenn schon nicht rauswerfen, dann vielleicht wenigstens die Standardbibliothek modularer gestalten, mit einem kleineren Kreis von ”core”-Modulen. Da wäre IMHO ein einfacheres Modul für ``async``/``await`` ein Vorteil. Koorperatives Multitasking wäre beispielsweise auch etwas wo Implementierungen wie MicroPython und Derivate von profitieren könnten, weil man auf den Plattformen ja in der Regel keine Threads verwenden kann und Einschränkungen bei Modulgrösse und Rechenleistung hat. Da wäre es schon schick wenn der gleiche Code in CPython und MicroPython mit der Standardbibliothek laufen würde.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Woraus leitest Du ab, dass `curio` nicht ernst gemeint sondern nur ein Experiment ist?
Natürlich ist es ein "ernst gemeintes" Projekt. Ich habe nichts anderes behauptet. Curio wird gewartet, und ist meines Wissens robust. Die Dokumentation ist umfangreich und gut.
Es scheint mir aber nicht viel genutzt zu werden und hat auch relativ wenig Aktivität.
Wie gesagt, ich halte es für eine Beispiel, Demo, Anschauungsobjekt, oder so. Es scheint auch kein Bestreben zu geben, mehr daraus zu machen als das was es zur Zeit ist.
Man kann aber als Anwender nicht so leicht aus mehreren Angeboten wählen wenn eines sehr stark dadurch hervorgehoben wird, dass es in der Standardbibliothek vorhanden ist.
Ich sehe kein Problem darin, dass es in der Standardbibliothek ist. Ich wüsste auch nicht, warum man versuchen sollte das Rad neu zu erfinden. Man kann auf asyncio aufbauen, ohne dass man unnötigen Balast hätte. Alles was asyncio bietet ist notwendig, und vollständig um als gute Basis für andere Frameworks zu dienen. TCP / UDP Protokolle sind richtigerweise in asyncio untergebracht. Alles was darauf aufsetzt, ist in externen Paketen untergebracht.
Es wird aus der Python-Dokumentation nicht so deutlich das ``async``/``await`` nicht nur mit `asyncio` in der Standardbibliothek funktionieren, sondern dass es Alternativen gibt, beziehungsweise geben könnte.
Dass es andere Möglichkeiten gibt, gehört auch nicht in die Dokumentation. Man will dort ja nicht die Entstehungsgeschichte und Rückwertskompatibilität dokumentieren. Für alle, die die Information wirklich brauchen, weil sie vielleicht ein älteres Framework an asyncio anpassen wollen, gibt es die PEP 492. Dort ist der genaue Hintergrund deutlich erklärt. Auch die Hintergründe, die zu der einen oder anderen Entscheidung bei der Entwicklung von asyncio geführt haben sind dort aufgeführt.
Du gehst einfach davon aus das `asyncio` einen Vorteil gegenüber anderen Bibliotheken haben muss, beziehungsweise die deswegen nicht bestehen.
Ich bin nicht sicher was du damit sagen willst. Ich gehe erstmal von gar nichts aus. Du hattest davon gesprochen, dass asyncio einen Vorteil hat weil es sich in der Standardbibliothek befindet. Wie ich ja schon sagt, sehe ich da keinen grundsätzlichen Vorteil. Mir ist gerade auch argparse und click eingefallen. Während argparse in der Standardbibliothek ist, muss click von extern installiert werden, dennoch sehe ich nicht dass click gemieden wird, nur weil es argparse schon in der Standardbibliothek gibt.
Es gibt einen offensichtlichen Bedarf für "Single-threaded concurrency". Tornado, Twisted, Trio, ... sind Belege für diesen Bedarf. Trio ist übrigens ein gutes Beispiel für ein Framework, dass sich entwickelt hat, nachdem asyncio in die Standardbibliothek kam.
Diese Frameworks haben alle die async - await Syntax übernommen, nicht weil sie dazu gezwungen sind, sondern weil es einfach naheliegend ist. Trio ist laut eigenen Angaben durch curio inspiriert und unabhängig von asyncio. Da ist also genau das entstanden, was du forderst, obwohl du selbst sagst, dass es durch die Dominanz von asyncio eigentlich nicht möglich wäre.

Ich denke das stellt klar, dass erstens die async - await Syntax nicht als störend sondern vereinfachend empfunden wird. Dass es Vorteile gibt, weil etwas in die Standardbibliothek integriert ist, ist in der Realität nicht nachvollziehbar.
Mir scheint als hättest du für dich entschieden, dass du einfach asyncio nicht brauchst oder es aus bestimmten Gründen ablehnst. Das ist zwar legitim, ich kann die Gründe aber nicht nachvollziehen.
Es gibt eine große Wahrscheinlichkeit, dass du selbst schon Pakete verwendest, die wiederum asyncio verwenden. Kann das sein? Wie auch immer, wenn du in deinen eignenen Projekten auf asycio verzichten willst, wird dir das sicher gelingen.
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Es geht nicht um Entwicklungsgeschichte und Rückwärtskompatibilität, sondern das die Leute gar nicht erst auf die Idee kommen es könnte etwas anderes als `asyncio` geben. Also weder die Leute die so etwas benutzen wollen, noch jemand der vielleicht was anderes, besseres schreiben würde. Und nicht alles was da definiert ist wird gebraucht und die API ist auch alles andere als minimal und auch nicht wirklich schön.

Natürlich kann es sein das ich `asyncio` irgendwann direkt oder indirekt verwende. Ich habe auch schon `xml.minidom` oder `xml.sax` direkt und indirekt verwendet. Und nun? Ist trotzdem keine gute API und die Leute die das genommen haben, haben das sicher nicht verwendet weil's so toll war, sondern weil es in der Standardbibliothek ist, und da sehr lange alleine war. Das Problem ist halt das `asyncio` in der Standardbibliothek und gut genug ist, was dazu führt das es Konkurrenten schwerer haben zu entstehen, sich zu entwickeln, Benutzer zu finden.

Bei `click` ist das etwas einfacher weil es in der Standardbibliothek nicht *die* Konkurrenz gibt, sondern gleich *drei* Alternativen! Auch so ein Beispiel was an der Standardbibliothek stinkt. Wenn das nicht gegen den einen offensichtlichen Weg spricht, dann weiss ich nicht was. Dadurch, dass es drei gibt, erhöht sich aber auch wieder ein bisschen die Chance, dass die Leute nicht einfach *das* *eine* Modul aus der Standardbibliothek nehmen und nicht auf die Idee kommen sich mal die Vor- und Nachteile der Alternativen anzuschauen und dabei eher auch auf externes aufmerksam werden.

In der Übersicht zu den Tk-Modulen steht, dass es auch andere GUI-Rahmenwerke gibt und es wird auf die entsprechende Übersichtsseite im Wiki von Python.org verlinkt. In der `urllib`-Dokumentation wird auf `requests` hingewiesen. Hinweise auf Alternativen gibt es in der Standardbibliothek also durchaus.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@__blackjack__, tja da kommt der Punkt wo wir halt unterschiedlicher Meinung sind.
Antworten