Seminarplatz
This commit is contained in:
		
							parent
							
								
									d5044da05c
								
							
						
					
					
						commit
						45a9a29083
					
				@ -1,240 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
 "cells": [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "markdown",
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "## Seminarplatz-Vergabe\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "In folgendem Problem geht es darum, dass eine Gruppe von Studierenden einen oder mehrere Seminarplätze in einem Kurs bekommen sollen. Es 8 Seminargruppen mit insgesamt 40 Plätzen, diese sind in der Tabelle `seminar_sessions` abgelegt.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "Bei einer Anmeldung einer einzelnen Person wird die Anzahl der Plätze in der Tabelle `seminar_sessions` um 1 reduziert und ein Eintrag in der Tabelle `seminar_registrations` erstellt. Dies darf natürlich nur passieren, wenn noch Plätze verfügbar sind.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` müssen konsistent sein, also in der Summe 40 ergeben.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "In einem Lasttest mit mehreren Threads zeigt sich: Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` sind nicht konsistent! \n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "### Ihre Aufgabe:\n",
 | 
					 | 
				
			||||||
    "Führen Sie geeignete Transaktionen ein, um die Konsistenz zu gewährleisten!\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "Implementierungen Sie dazu zunächst die Funktionen, die mit TODO gekennzeichnet sind, und passen Sie die Funktion `reserve_seat` an, um die Konsistenz zu gewährleisten.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "Am Code des Lasttests müssen Sie nichts ändern, er dient nur dazu, das Problem zu demonstrieren.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "### Bemerkungen:\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "- nicht jeder Durchlauf verursacht Inkonsistenzen, manchmal müssen Sie den Code mehrmals ausführen, um Inkonsistenzen zu finden\n",
 | 
					 | 
				
			||||||
    "- auch Deadlocks können auftreten, diese müssen auch vermieden werden\n",
 | 
					 | 
				
			||||||
    "- die User-Tabelle wurde weggelassen, da sie für das Problem nicht relevant ist\n",
 | 
					 | 
				
			||||||
    "- an manchen Stellen ist der Code absichtlich etwas ineffizient gehalten, um die Inkonsistenzen zu begünstigen (z.B. würden Probleme mit Inkonsistenzen seltener auftreten, wenn die Query `UPDATE seminar_sessions SET seats = seats-1` lauten würde).\n",
 | 
					 | 
				
			||||||
    "\n"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "import psycopg2\n",
 | 
					 | 
				
			||||||
    "import psycopg2.extras"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "# Datenbankverbindung herstellen\n",
 | 
					 | 
				
			||||||
    "def get_connection():\n",
 | 
					 | 
				
			||||||
    "  # TODO Datenbankverbindung herstellen - geben Sie hier Ihre Zugangsdaten ein\n",
 | 
					 | 
				
			||||||
    "  conn = psycopg2.connect(\"dbname=... user=... password=...\")\n",
 | 
					 | 
				
			||||||
    "  \n",
 | 
					 | 
				
			||||||
    "  # TODO später autocommit ausschalten\n",
 | 
					 | 
				
			||||||
    "  conn.autocommit = True\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "  return conn"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "# Tabelle erzeugen - immer wenn diese Zelle ausgeführt wird, wird die Tabelle neu erzeugt\n",
 | 
					 | 
				
			||||||
    "conn = get_connection()\n",
 | 
					 | 
				
			||||||
    "cursor = conn.cursor()\n",
 | 
					 | 
				
			||||||
    "cursor.execute(\"\"\"\n",
 | 
					 | 
				
			||||||
    "              DROP TABLE IF EXISTS seminar_registrations CASCADE;\n",
 | 
					 | 
				
			||||||
    "              DROP TABLE IF EXISTS seminar_sessions;\n",
 | 
					 | 
				
			||||||
    "               \n",
 | 
					 | 
				
			||||||
    "              CREATE TABLE IF NOT EXISTS seminar_sessions (\n",
 | 
					 | 
				
			||||||
    "                  id SERIAL PRIMARY KEY, \n",
 | 
					 | 
				
			||||||
    "                  seats INTEGER NOT NULL\n",
 | 
					 | 
				
			||||||
    "              );\n",
 | 
					 | 
				
			||||||
    "                  \n",
 | 
					 | 
				
			||||||
    "              INSERT INTO seminar_sessions (seats) VALUES \n",
 | 
					 | 
				
			||||||
    "                  (4), (4), (5), (5), (4), (10), (5), (3);\n",
 | 
					 | 
				
			||||||
    "               \n",
 | 
					 | 
				
			||||||
    "              \n",
 | 
					 | 
				
			||||||
    "              CREATE TABLE IF NOT EXISTS seminar_registrations (\n",
 | 
					 | 
				
			||||||
    "                  user_id INTEGER NOT NULL,\n",
 | 
					 | 
				
			||||||
    "                  session_id INTEGER NOT NULL,\n",
 | 
					 | 
				
			||||||
    "                  FOREIGN KEY (session_id) REFERENCES seminar_sessions(id)\n",
 | 
					 | 
				
			||||||
    "              );          \n",
 | 
					 | 
				
			||||||
    "\"\"\")\n",
 | 
					 | 
				
			||||||
    "conn.commit()"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "# Hilfsfunktion: Alle Seminar-Sessions ausgeben\n",
 | 
					 | 
				
			||||||
    "def show_sessions():\n",
 | 
					 | 
				
			||||||
    "    # TODO alle Seminar-Sessions auf der Console ausgeben\n",
 | 
					 | 
				
			||||||
    "    pass\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Anzahl aller freien Plätze bestimmen\n",
 | 
					 | 
				
			||||||
    "def count_free_seats():\n",
 | 
					 | 
				
			||||||
    "    # TODO Anzahl freier Plätze bestimmen (Summe über die Spalte \"seats\")\n",
 | 
					 | 
				
			||||||
    "    # und mit return zurückgeben\n",
 | 
					 | 
				
			||||||
    "    pass\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Anzahl der belegten Plätze bestimmen\n",
 | 
					 | 
				
			||||||
    "def count_occupied_seats():\n",
 | 
					 | 
				
			||||||
    "    # TODO Anzahl belegter Plätze bestimmen (Anzahl der Einträge in der Tabelle seminar_registrations)\n",
 | 
					 | 
				
			||||||
    "    # und mit return zurückgeben\n",
 | 
					 | 
				
			||||||
    "    pass\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Testaufrufe\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# show_sessions()\n",
 | 
					 | 
				
			||||||
    "# print(\"freie Plätze\", count_free_seats())\n",
 | 
					 | 
				
			||||||
    "# print(\"belegte Plätze\", count_occupied_seats())"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "# Diese Funktion soll einen Platz reservieren und True zurückgeben, wenn es geklappt hat.\n",
 | 
					 | 
				
			||||||
    "# Wenn kein Platz mehr frei ist, soll False zurückgegeben werden.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# TODO: Führen Sie geeignete Transaktionssteuerung ein, um sicherzustellen, dass die Funktion korrekt arbeitet.\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "def reserve_seat(conn, user_id, session_id):\n",
 | 
					 | 
				
			||||||
    "    with conn.cursor() as cursor:\n",
 | 
					 | 
				
			||||||
    "        cursor.execute(\"SELECT seats FROM seminar_sessions WHERE id = %s\", (session_id,))\n",
 | 
					 | 
				
			||||||
    "        seats = cursor.fetchone()[0]\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "        if seats > 0:\n",
 | 
					 | 
				
			||||||
    "            cursor.execute(\"UPDATE seminar_sessions SET seats = %s WHERE id = %s\", (seats-1, session_id,))\n",
 | 
					 | 
				
			||||||
    "            cursor.execute(\"INSERT INTO seminar_registrations (user_id, session_id) VALUES (%s, %s)\", (user_id, session_id))\n",
 | 
					 | 
				
			||||||
    "            return True\n",
 | 
					 | 
				
			||||||
    "        else:\n",
 | 
					 | 
				
			||||||
    "            return False\n",
 | 
					 | 
				
			||||||
    "        \n"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "import random \n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# 20 zufällige Anmeldungen durchführen - diese Funktion wird später als Thread gestartet\n",
 | 
					 | 
				
			||||||
    "def random_seat_reservation(n=20):\n",
 | 
					 | 
				
			||||||
    "    # jeder Thread hat seine eigene Verbindung\n",
 | 
					 | 
				
			||||||
    "    conn = get_connection()\n",
 | 
					 | 
				
			||||||
    "    \n",
 | 
					 | 
				
			||||||
    "    # n mal einen zufälligen Platz für eine zufällige User-ID reservieren\n",
 | 
					 | 
				
			||||||
    "    for _ in range(n):\n",
 | 
					 | 
				
			||||||
    "        random_user_id = random.randint(1, 100)\n",
 | 
					 | 
				
			||||||
    "        random_session_id = random.randint(1, 8)\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "        if reserve_seat(conn, random_user_id, random_session_id):\n",
 | 
					 | 
				
			||||||
    "            print(\"User\", random_user_id, \"hat sich für Session\", random_session_id, \"angemeldet\")\n",
 | 
					 | 
				
			||||||
    "        else:\n",
 | 
					 | 
				
			||||||
    "            print(\"Session\", random_session_id, \"ist ausgebucht\")"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": null,
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "import threading\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Diese Funktion gibt Informationen über die Belegung der Seminare aus\n",
 | 
					 | 
				
			||||||
    "def print_info():\n",
 | 
					 | 
				
			||||||
    "    print('-'*20)\n",
 | 
					 | 
				
			||||||
    "    \n",
 | 
					 | 
				
			||||||
    "    free_seats = count_free_seats()\n",
 | 
					 | 
				
			||||||
    "    occupied_seats = count_occupied_seats()\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "    print(\"Freie Plätze:\", free_seats)\n",
 | 
					 | 
				
			||||||
    "    print(\"Belegte Plätze:\", occupied_seats)\n",
 | 
					 | 
				
			||||||
    "    print(\"Gesamt:\", free_seats + occupied_seats)\n",
 | 
					 | 
				
			||||||
    "    \n",
 | 
					 | 
				
			||||||
    "    if free_seats + occupied_seats == 40:\n",
 | 
					 | 
				
			||||||
    "        print(\"Platzanzahl ist konsistent!\")\n",
 | 
					 | 
				
			||||||
    "    else:\n",
 | 
					 | 
				
			||||||
    "        print(\"Platzanzahl ist inkonsistent!\")\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "    print('-'*20)\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# -------------------------------------------------------------------------\n",
 | 
					 | 
				
			||||||
    "# Mini-Lasttest, 5 Threads starten, die jeweils 20 Reservierungen vornehmen\n",
 | 
					 | 
				
			||||||
    "# -------------------------------------------------------------------------\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "print(\"Vor dem Lasttest:\")\n",
 | 
					 | 
				
			||||||
    "print_info()\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "threads = [ threading.Thread(target=random_seat_reservation) for _ in range(5)]\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Threads starten\n",
 | 
					 | 
				
			||||||
    "for t in threads:\n",
 | 
					 | 
				
			||||||
    "    t.start()\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "# Auf das Ende der Threads warten\n",
 | 
					 | 
				
			||||||
    "for t in threads:\n",
 | 
					 | 
				
			||||||
    "    t.join()\n",
 | 
					 | 
				
			||||||
    "\n",
 | 
					 | 
				
			||||||
    "    \n",
 | 
					 | 
				
			||||||
    "print(\"Nach dem Lasttest:\")\n",
 | 
					 | 
				
			||||||
    "print_info()"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 ],
 | 
					 | 
				
			||||||
 "metadata": {
 | 
					 | 
				
			||||||
  "kernelspec": {
 | 
					 | 
				
			||||||
   "display_name": "base",
 | 
					 | 
				
			||||||
   "language": "python",
 | 
					 | 
				
			||||||
   "name": "python3"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "language_info": {
 | 
					 | 
				
			||||||
   "codemirror_mode": {
 | 
					 | 
				
			||||||
    "name": "ipython",
 | 
					 | 
				
			||||||
    "version": 3
 | 
					 | 
				
			||||||
   },
 | 
					 | 
				
			||||||
   "file_extension": ".py",
 | 
					 | 
				
			||||||
   "mimetype": "text/x-python",
 | 
					 | 
				
			||||||
   "name": "python",
 | 
					 | 
				
			||||||
   "nbconvert_exporter": "python",
 | 
					 | 
				
			||||||
   "pygments_lexer": "ipython3",
 | 
					 | 
				
			||||||
   "version": "3.11.7"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 },
 | 
					 | 
				
			||||||
 "nbformat": 4,
 | 
					 | 
				
			||||||
 "nbformat_minor": 2
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										391
									
								
								code/online-part-2a/FS25 _Seminarplatz_Vergabe.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								code/online-part-2a/FS25 _Seminarplatz_Vergabe.ipynb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,391 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					 "cells": [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "markdown",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "## Seminarplatz-Vergabe\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "In folgendem Problem geht es darum, dass eine Gruppe von Studierenden einen oder mehrere Seminarplätze in einem Kurs bekommen sollen. Es 8 Seminargruppen mit insgesamt 40 Plätzen, diese sind in der Tabelle `seminar_sessions` abgelegt.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "Bei einer Anmeldung einer einzelnen Person wird die Anzahl der Plätze in der Tabelle `seminar_sessions` um 1 reduziert und ein Eintrag in der Tabelle `seminar_registrations` erstellt. Dies darf natürlich nur passieren, wenn noch Plätze verfügbar sind.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` müssen konsistent sein, also in der Summe 40 ergeben.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "In einem Lasttest mit mehreren Threads zeigt sich: Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` sind nicht konsistent! \n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "### Ihre Aufgabe:\n",
 | 
				
			||||||
 | 
					    "Führen Sie geeignete Transaktionen ein, um die Konsistenz zu gewährleisten!\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "Implementierungen Sie dazu zunächst die Funktionen, die mit TODO gekennzeichnet sind, und passen Sie die Funktion `reserve_seat` an, um die Konsistenz zu gewährleisten.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "Am Code des Lasttests müssen Sie nichts ändern, er dient nur dazu, das Problem zu demonstrieren.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "### Bemerkungen:\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "- nicht jeder Durchlauf verursacht Inkonsistenzen, manchmal müssen Sie den Code mehrmals ausführen, um Inkonsistenzen zu finden\n",
 | 
				
			||||||
 | 
					    "- auch Deadlocks können auftreten, diese müssen auch vermieden werden\n",
 | 
				
			||||||
 | 
					    "- die User-Tabelle wurde weggelassen, da sie für das Problem nicht relevant ist\n",
 | 
				
			||||||
 | 
					    "- an manchen Stellen ist der Code absichtlich etwas ineffizient gehalten, um die Inkonsistenzen zu begünstigen (z.B. würden Probleme mit Inkonsistenzen seltener auftreten, wenn die Query `UPDATE seminar_sessions SET seats = seats-1` lauten würde).\n",
 | 
				
			||||||
 | 
					    "\n"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 16,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "import psycopg2\n",
 | 
				
			||||||
 | 
					    "import psycopg2.extras"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 17,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "# Datenbankverbindung herstellen\n",
 | 
				
			||||||
 | 
					    "def get_connection():\n",
 | 
				
			||||||
 | 
					    "    conn =  psycopg2.connect(\n",
 | 
				
			||||||
 | 
					    "        host=\"localhost\",\n",
 | 
				
			||||||
 | 
					    "        port=5432,\n",
 | 
				
			||||||
 | 
					    "        dbname=\"postgres\",\n",
 | 
				
			||||||
 | 
					    "        user=\"postgres\",\n",
 | 
				
			||||||
 | 
					    "        password=\"postgres\",\n",
 | 
				
			||||||
 | 
					    "    )\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    conn.autocommit = False\n",
 | 
				
			||||||
 | 
					    "    return conn"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 18,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "# Tabelle erzeugen - immer wenn diese Zelle ausgeführt wird, wird die Tabelle neu erzeugt\n",
 | 
				
			||||||
 | 
					    "conn = get_connection()\n",
 | 
				
			||||||
 | 
					    "cursor = conn.cursor()\n",
 | 
				
			||||||
 | 
					    "cursor.execute(\"\"\"\n",
 | 
				
			||||||
 | 
					    "              DROP TABLE IF EXISTS seminar_registrations CASCADE;\n",
 | 
				
			||||||
 | 
					    "              DROP TABLE IF EXISTS seminar_sessions;\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "              CREATE TABLE IF NOT EXISTS seminar_sessions (\n",
 | 
				
			||||||
 | 
					    "                  id SERIAL PRIMARY KEY,\n",
 | 
				
			||||||
 | 
					    "                  seats INTEGER NOT NULL\n",
 | 
				
			||||||
 | 
					    "              );\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "              INSERT INTO seminar_sessions (seats) VALUES\n",
 | 
				
			||||||
 | 
					    "                  (4), (4), (5), (5), (4), (10), (5), (3);\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "              CREATE TABLE IF NOT EXISTS seminar_registrations (\n",
 | 
				
			||||||
 | 
					    "                  user_id INTEGER NOT NULL,\n",
 | 
				
			||||||
 | 
					    "                  session_id INTEGER NOT NULL,\n",
 | 
				
			||||||
 | 
					    "                  FOREIGN KEY (session_id) REFERENCES seminar_sessions(id)\n",
 | 
				
			||||||
 | 
					    "              );\n",
 | 
				
			||||||
 | 
					    "\"\"\")\n",
 | 
				
			||||||
 | 
					    "conn.commit()"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 19,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "name": "stdout",
 | 
				
			||||||
 | 
					     "output_type": "stream",
 | 
				
			||||||
 | 
					     "text": [
 | 
				
			||||||
 | 
					      "Session 1: 4 free seats\n",
 | 
				
			||||||
 | 
					      "Session 2: 4 free seats\n",
 | 
				
			||||||
 | 
					      "Session 3: 5 free seats\n",
 | 
				
			||||||
 | 
					      "Session 4: 5 free seats\n",
 | 
				
			||||||
 | 
					      "Session 5: 4 free seats\n",
 | 
				
			||||||
 | 
					      "Session 6: 10 free seats\n",
 | 
				
			||||||
 | 
					      "Session 7: 5 free seats\n",
 | 
				
			||||||
 | 
					      "Session 8: 3 free seats\n",
 | 
				
			||||||
 | 
					      "freie Plätze 40\n",
 | 
				
			||||||
 | 
					      "belegte Plätze 0\n"
 | 
				
			||||||
 | 
					     ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "# Hilfsfunktion: Alle Seminar-Sessions ausgeben\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Task: Alle Seminar-Sessions auf der Console ausgeben\n",
 | 
				
			||||||
 | 
					    "def show_sessions():\n",
 | 
				
			||||||
 | 
					    "    with (\n",
 | 
				
			||||||
 | 
					    "        get_connection() as conn,\n",
 | 
				
			||||||
 | 
					    "        conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur,\n",
 | 
				
			||||||
 | 
					    "    ):\n",
 | 
				
			||||||
 | 
					    "        cur.execute(\"SELECT id, seats FROM seminar_sessions ORDER BY id\")\n",
 | 
				
			||||||
 | 
					    "        for row in cur.fetchall():\n",
 | 
				
			||||||
 | 
					    "            print(f\"Session {row['id']}: {row['seats']} free seats\")\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Anzahl aller freien Plätze bestimmen\n",
 | 
				
			||||||
 | 
					    "# Task: Anzahl freier Plätze bestimmen (Summe über die Spalte \"seats\")\n",
 | 
				
			||||||
 | 
					    "def count_free_seats():\n",
 | 
				
			||||||
 | 
					    "    with get_connection() as conn, conn.cursor() as cur:\n",
 | 
				
			||||||
 | 
					    "        cur.execute(\"SELECT COALESCE(SUM(seats), 0) FROM seminar_sessions\")\n",
 | 
				
			||||||
 | 
					    "        return cur.fetchone()[0]\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Anzahl der belegten Plätze bestimmen\n",
 | 
				
			||||||
 | 
					    "# Task: Anzahl belegter Plätze bestimmen (Anzahl der Einträge in der Tabelle seminar_registrations)\n",
 | 
				
			||||||
 | 
					    "def count_occupied_seats():\n",
 | 
				
			||||||
 | 
					    "    with get_connection() as conn, conn.cursor() as cur:\n",
 | 
				
			||||||
 | 
					    "        cur.execute(\"SELECT COUNT(*) FROM seminar_registrations\")\n",
 | 
				
			||||||
 | 
					    "        return cur.fetchone()[0]\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Testaufrufe\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# show_sessions()\n",
 | 
				
			||||||
 | 
					    "show_sessions()\n",
 | 
				
			||||||
 | 
					    "print(\"freie Plätze\", count_free_seats())\n",
 | 
				
			||||||
 | 
					    "print(\"belegte Plätze\", count_occupied_seats())"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 20,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "# Diese Funktion reserviert einen Platz in einer Transaktion.\n",
 | 
				
			||||||
 | 
					    "def reserve_seat(conn, user_id, session_id):\n",
 | 
				
			||||||
 | 
					    "    \"\"\"Versucht, einen Seminarplatz für den gegebenen Benutzer in der angegebenen Session zu reservieren.\n",
 | 
				
			||||||
 | 
					    "    Gibt True zurück, wenn die Reservierung erfolgreich war, sonst False. Die Operation wird in einer\n",
 | 
				
			||||||
 | 
					    "    transaktionalen Einheit ausgeführt, um Inkonsistenzen zu vermeiden.\"\"\"\n",
 | 
				
			||||||
 | 
					    "    with conn:\n",
 | 
				
			||||||
 | 
					    "        with conn.cursor() as cur:\n",
 | 
				
			||||||
 | 
					    "            cur.execute(\"SELECT seats FROM seminar_sessions WHERE id = %s FOR UPDATE\", (session_id,))\n",
 | 
				
			||||||
 | 
					    "            seats = cur.fetchone()[0]\n",
 | 
				
			||||||
 | 
					    "            if seats <= 0:\n",
 | 
				
			||||||
 | 
					    "                return False\n",
 | 
				
			||||||
 | 
					    "            cur.execute(\"UPDATE seminar_sessions SET seats = seats - 1 WHERE id = %s\", (session_id,))\n",
 | 
				
			||||||
 | 
					    "            cur.execute(\n",
 | 
				
			||||||
 | 
					    "                \"INSERT INTO seminar_registrations (user_id, session_id) VALUES (%s, %s)\",\n",
 | 
				
			||||||
 | 
					    "                (user_id, session_id)\n",
 | 
				
			||||||
 | 
					    "            )\n",
 | 
				
			||||||
 | 
					    "            return True\n"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 21,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "import random\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# 20 zufällige Anmeldungen durchführen - diese Funktion wird später als Thread gestartet\n",
 | 
				
			||||||
 | 
					    "def random_seat_reservation(n=20):\n",
 | 
				
			||||||
 | 
					    "    # jeder Thread hat seine eigene Verbindung\n",
 | 
				
			||||||
 | 
					    "    conn = get_connection()\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    # n mal einen zufälligen Platz für eine zufällige User-ID reservieren\n",
 | 
				
			||||||
 | 
					    "    for _ in range(n):\n",
 | 
				
			||||||
 | 
					    "        random_user_id = random.randint(1, 100)\n",
 | 
				
			||||||
 | 
					    "        random_session_id = random.randint(1, 8)\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "        if reserve_seat(conn, random_user_id, random_session_id):\n",
 | 
				
			||||||
 | 
					    "            print(\"User\", random_user_id, \"hat sich für Session\", random_session_id, \"angemeldet\")\n",
 | 
				
			||||||
 | 
					    "        else:\n",
 | 
				
			||||||
 | 
					    "            print(\"Session\", random_session_id, \"ist ausgebucht\")"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 22,
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "name": "stdout",
 | 
				
			||||||
 | 
					     "output_type": "stream",
 | 
				
			||||||
 | 
					     "text": [
 | 
				
			||||||
 | 
					      "Vor dem Lasttest:\n",
 | 
				
			||||||
 | 
					      "--------------------\n",
 | 
				
			||||||
 | 
					      "Freie Plätze: 40\n",
 | 
				
			||||||
 | 
					      "Belegte Plätze: 0\n",
 | 
				
			||||||
 | 
					      "Gesamt: 40\n",
 | 
				
			||||||
 | 
					      "Platzanzahl ist konsistent!\n",
 | 
				
			||||||
 | 
					      "--------------------\n",
 | 
				
			||||||
 | 
					      "User 25 hat sich für Session 3 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 25 hat sich für Session 4 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 31 hat sich für Session 8 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 91 hat sich für Session 2 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 66 hat sich für Session 1 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 61 hat sich für Session 3 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 53 hat sich für Session 7 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 70 hat sich für Session 4 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 98 hat sich für Session 3 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 42 hat sich für Session 5 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 22 hat sich für Session 7 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 71 hat sich für Session 3 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 50 hat sich für Session 2 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 26 hat sich für Session 1 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 53 hat sich für Session 5 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 54 hat sich für Session 4 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 72 hat sich für Session 1 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 3 hat sich für Session 3 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 95 hat sich für Session 7 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 83 hat sich für Session 4 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 90 hat sich für Session 7 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 78 hat sich für Session 1 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 14 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 84 hat sich für Session 7 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 75 hat sich für Session 8 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 97 hat sich für Session 4 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 93 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 28 hat sich für Session 2 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 92 hat sich für Session 8 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 88 hat sich für Session 5 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 64 hat sich für Session 2 angemeldet\n",
 | 
				
			||||||
 | 
					      "User 14 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 74 hat sich für Session 5 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 4 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 4 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 49 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 23 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 9 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 4 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 13 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "User 73 hat sich für Session 6 angemeldet\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 8 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 4 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 4 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 3 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 2 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 1 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 7 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Session 5 ist ausgebucht\n",
 | 
				
			||||||
 | 
					      "Nach dem Lasttest:\n",
 | 
				
			||||||
 | 
					      "--------------------\n",
 | 
				
			||||||
 | 
					      "Freie Plätze: 2\n",
 | 
				
			||||||
 | 
					      "Belegte Plätze: 38\n",
 | 
				
			||||||
 | 
					      "Gesamt: 40\n",
 | 
				
			||||||
 | 
					      "Platzanzahl ist konsistent!\n",
 | 
				
			||||||
 | 
					      "--------------------\n"
 | 
				
			||||||
 | 
					     ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "import threading\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Diese Funktion gibt Informationen über die Belegung der Seminare aus\n",
 | 
				
			||||||
 | 
					    "def print_info():\n",
 | 
				
			||||||
 | 
					    "    print('-'*20)\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    free_seats = count_free_seats()\n",
 | 
				
			||||||
 | 
					    "    occupied_seats = count_occupied_seats()\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    print(\"Freie Plätze:\", free_seats)\n",
 | 
				
			||||||
 | 
					    "    print(\"Belegte Plätze:\", occupied_seats)\n",
 | 
				
			||||||
 | 
					    "    print(\"Gesamt:\", free_seats + occupied_seats)\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    if free_seats + occupied_seats == 40:\n",
 | 
				
			||||||
 | 
					    "        print(\"Platzanzahl ist konsistent!\")\n",
 | 
				
			||||||
 | 
					    "    else:\n",
 | 
				
			||||||
 | 
					    "        print(\"Platzanzahl ist inkonsistent!\")\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    print('-'*20)\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# -------------------------------------------------------------------------\n",
 | 
				
			||||||
 | 
					    "# Mini-Lasttest, 5 Threads starten, die jeweils 20 Reservierungen vornehmen\n",
 | 
				
			||||||
 | 
					    "# -------------------------------------------------------------------------\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "print(\"Vor dem Lasttest:\")\n",
 | 
				
			||||||
 | 
					    "print_info()\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "threads = [ threading.Thread(target=random_seat_reservation) for _ in range(5)]\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Threads starten\n",
 | 
				
			||||||
 | 
					    "for t in threads:\n",
 | 
				
			||||||
 | 
					    "    t.start()\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "# Auf das Ende der Threads warten\n",
 | 
				
			||||||
 | 
					    "for t in threads:\n",
 | 
				
			||||||
 | 
					    "    t.join()\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "print(\"Nach dem Lasttest:\")\n",
 | 
				
			||||||
 | 
					    "print_info()"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 ],
 | 
				
			||||||
 | 
					 "metadata": {
 | 
				
			||||||
 | 
					  "kernelspec": {
 | 
				
			||||||
 | 
					   "display_name": "code (3.13.2)",
 | 
				
			||||||
 | 
					   "language": "python",
 | 
				
			||||||
 | 
					   "name": "python3"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "language_info": {
 | 
				
			||||||
 | 
					   "codemirror_mode": {
 | 
				
			||||||
 | 
					    "name": "ipython",
 | 
				
			||||||
 | 
					    "version": 3
 | 
				
			||||||
 | 
					   },
 | 
				
			||||||
 | 
					   "file_extension": ".py",
 | 
				
			||||||
 | 
					   "mimetype": "text/x-python",
 | 
				
			||||||
 | 
					   "name": "python",
 | 
				
			||||||
 | 
					   "nbconvert_exporter": "python",
 | 
				
			||||||
 | 
					   "pygments_lexer": "ipython3",
 | 
				
			||||||
 | 
					   "version": "3.13.3"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 },
 | 
				
			||||||
 | 
					 "nbformat": 4,
 | 
				
			||||||
 | 
					 "nbformat_minor": 2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -7,5 +7,6 @@ dependencies = [
 | 
				
			|||||||
    "matplotlib>=3.10.3",
 | 
					    "matplotlib>=3.10.3",
 | 
				
			||||||
    "numpy>=2.2.5",
 | 
					    "numpy>=2.2.5",
 | 
				
			||||||
    "pandas>=2.2.3",
 | 
					    "pandas>=2.2.3",
 | 
				
			||||||
 | 
					    "psycopg2>=2.9.10",
 | 
				
			||||||
    "pymongo>=4.12.1",
 | 
					    "pymongo>=4.12.1",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								code/uv.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								code/uv.lock
									
									
									
										generated
									
									
									
								
							@ -51,6 +51,7 @@ dependencies = [
 | 
				
			|||||||
    { name = "matplotlib" },
 | 
					    { name = "matplotlib" },
 | 
				
			||||||
    { name = "numpy" },
 | 
					    { name = "numpy" },
 | 
				
			||||||
    { name = "pandas" },
 | 
					    { name = "pandas" },
 | 
				
			||||||
 | 
					    { name = "psycopg2" },
 | 
				
			||||||
    { name = "pymongo" },
 | 
					    { name = "pymongo" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -60,6 +61,7 @@ requires-dist = [
 | 
				
			|||||||
    { name = "matplotlib", specifier = ">=3.10.3" },
 | 
					    { name = "matplotlib", specifier = ">=3.10.3" },
 | 
				
			||||||
    { name = "numpy", specifier = ">=2.2.5" },
 | 
					    { name = "numpy", specifier = ">=2.2.5" },
 | 
				
			||||||
    { name = "pandas", specifier = ">=2.2.3" },
 | 
					    { name = "pandas", specifier = ">=2.2.3" },
 | 
				
			||||||
 | 
					    { name = "psycopg2", specifier = ">=2.9.10" },
 | 
				
			||||||
    { name = "pymongo", specifier = ">=4.12.1" },
 | 
					    { name = "pymongo", specifier = ">=4.12.1" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -519,6 +521,15 @@ wheels = [
 | 
				
			|||||||
    { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 },
 | 
					    { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "psycopg2"
 | 
				
			||||||
 | 
					version = "2.9.10"
 | 
				
			||||||
 | 
					source = { registry = "https://pypi.org/simple" }
 | 
				
			||||||
 | 
					sdist = { url = "https://files.pythonhosted.org/packages/62/51/2007ea29e605957a17ac6357115d0c1a1b60c8c984951c19419b3474cdfd/psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11", size = 385672 }
 | 
				
			||||||
 | 
					wheels = [
 | 
				
			||||||
 | 
					    { url = "https://files.pythonhosted.org/packages/ae/49/a6cfc94a9c483b1fa401fbcb23aca7892f60c7269c5ffa2ac408364f80dc/psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2", size = 2569060 },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "ptyprocess"
 | 
					name = "ptyprocess"
 | 
				
			||||||
version = "0.7.0"
 | 
					version = "0.7.0"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user