Seite 1 von 1
Mein RSS-Feed-Lese-Thread-Thread
Verfasst: Montag 29. September 2008, 11:14
von __marcus__
Leider hab ich auf meinem Rechner nicht MySQLdb installiert, deswegen teste ich das auf dem Server und weiß von daher z.B. nicht, ob das bei mir vielleicht laufen würde. Aber bei dem Skript hier bekomme mal die eine mal die andere Fehlermeldung aus dem Titel. Allerdings auch keine Stelle, wo das passiert, was ich noch nie gehabt habe und nicht wirklich einordnen kann.
Ist mein Code denn soweit OK? (Und kann mir bei der Gelegenheit vielleicht auch jemand sagen, wie ich die letzte auskommentierte Zeile einbauen müsste, damit die nicht geschlossen werden, während die Threads noch laufen?)
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import MySQLdb, feedparser, sys
from threading import Thread
class getNews(Thread):
def __init__ (self,url):
Thread.__init__(self)
self.url = url
def run(self):
feed = feedparser.parse(self.url)
for entry in feed.entries:
try:
cursor.execute('INSERT INTO nachrichten(titel, url) VALUES("%s", "%s")', (entry.title.replace('\n', ' '), entry.link))
except:
pass
try:
db = MySQLdb.connect(host = 'rdbms.strato.de', user = 'HANNOVER96', passwd = 'muttisliebling', db = 'KGB567125')
cursor = db.cursor()
except:
sys.exit('Could not connect to database server')
cursor.execute('SELECT url FROM feedquellen')
for response in cursor:
t = getNews(response[0])
t.start()
# cursor.close(); db.close();
Verfasst: Montag 29. September 2008, 11:42
von BlackJack
PEP 249 ─ Python Database API Specification v2.0 sagt zum Thema "threadsafety":
Code: Alles auswählen
threadsafety
Integer constant stating the level of thread safety the
interface supports. Possible values are:
0 Threads may not share the module.
1 Threads may share the module, but not connections.
2 Threads may share the module and connections.
3 Threads may share the module, connections and
cursors.
Und `MySQLdb`:
Du kannst also weder Verbindungen noch Cursor von mehreren Threads aus verwenden.
Falls das ginge, um die zweite Frage zu beantworten, müsste vor das Schliessen eine Schleife, die auf alle Threads wartet. Siehe `Thread.join()`.
PS: Eventuell ist eine Lösung mit `executemany()` schneller und ich sehe nirgends ein `commit()`!?
Verfasst: Dienstag 30. September 2008, 23:39
von __marcus__
Danke Dir.
Verfasst: Mittwoch 1. Oktober 2008, 13:00
von Sr4l
BlackJack hat geschrieben:PS: Eventuell ist eine Lösung mit `executemany()` schneller und ich sehe nirgends ein `commit()`!?
http://dev.mysql.com/doc/refman/5.1/de/commit.html hat geschrieben:
Standardmäßig läuft MySQL im Autocommit-Modus. Das bedeutet, dass, sobald eine Anweisung ausgeführt wird, die eine Tabelle aktualisiert (also ändert), MySQL diese Änderung auf Festplatte speichert.
Verwenden Sie eine transaktionssichere Speicher-Engine (wie InnoDB, BDB oder NDB Cluster), dann können Sie den Autocommit-Modus mit der folgenden Anweisung deaktivieren:
SET AUTOCOMMIT=0;
Nach der Deaktivierung des Autocommit-Modus durch Setzen der AUTOCOMMIT-Variablen auf Null müssen Sie Ihre Änderungen mit COMMIT auf Festplatte speichern oder mit ROLLBACK rückgängig machen, wenn Sie die seit Beginn der Transaktion vorgenommenen Änderungen nicht übernehmen wollen.
Man braucht also bei MySQL in manchen Fällen kein commit.
Hat mich (vor einiger Zeit) auch gewundert.
Verfasst: Mittwoch 1. Oktober 2008, 13:31
von BlackJack
Man braucht es nicht, aber es schadet auch nicht und die Python DB-API 2.0 schreibt vor, dass Transaktionen aktiviert sein sollten wenn die Datenbank das kann, und das `Connection.commit()` als Leeroperation implementiert werden sollte falls die Datenbank keine Transaktionen kann.
Verfasst: Donnerstag 2. Oktober 2008, 17:09
von __marcus__
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import MySQLdb, feedparser, sys, threading
news = [] # Hier schreiben die Threads die RSS-Titel samt Link rein
threads = [] # Liste um mit .join() auf alle Threads warten zu können
class getNews(threading.Thread):
newslock = threading.Lock()
def __init__ (self,url):
threading.Thread.__init__(self)
self.url = url
def run(self):
try:
feed = feedparser.parse(self.url)
for entry in feed.entries:
getNews.newslock.acquire()
news.append((entry.title, entry.link))
getNews.newslock.release()
except:
pass
if __name__ == "__main__":
try:
db = MySQLdb.connect(host = 'rdbms.strato.de', user = '', passwd = '', db = '')
cursor = db.cursor()
except:
sys.exit('Could not connect to database server')
cursor.execute('SELECT url FROM feedquellen')
for response in cursor:
t = getNews(response[0])
threads.append(t)
t.start()
for t in threads:
t.join(60)
for n in news:
try:
cursor.execute('INSERT INTO nachrichten(titel, url) VALUES("%s", "%s")', (n[0], n[1]))
except:
pass
cursor.close(); db.close();
Das ist jetzt im großen und ganzen aus meinem RSS-Feed-Lese-Thread geworden, aber es stellen sich mir leider neue Fragen:
- Hab ich das mit newslock.acquire() richtig gemacht und ist das auch erforderlich hier?
- Die url-Spalte in meiner DB ist "unique" und executemany steigt beim ersten doppelten Eintrag aus. Kann ich das verhindern oder muss ich das dann mit der Schleife machen?
Edit:
Kann mir bitte vielleicht noch jemand die zwei verbliebenen Fragen beantworten?