Seite 1 von 1

bringen mir threads was ?

Verfasst: Dienstag 11. Dezember 2007, 14:06
von debian75
ich bin für eine web applikation zu python gewechelt, weil in php keine threads möglich sind.

ich will ca. 20 urls gleichzeitig ansprechen und nach verfügbarkeiten vo produkten fragen (ähnlich preisvergleich seiten, die zig shops absuchen)

jetzt hatte ich mir vorgestellt das mit threads zu machen, lese aber folgendes in der mailing list von python
Because of the GIL, thread pools are not as useful in Python as you
might expect -- they execute one at a time and do not take advantage of
hyper-threading or multiple processors. If that kind of efficiency is
what you are after, then take a look at PyLinda which can coordinate
communication between multiple instances of Python running in separate
threads
was heisst "they execute one at the time" ? das macht ja mal gar keinen sinn dann.

im moment starte ich gleich viele threads wie ich urls habe, nach diesem beispiel von gerold:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import urllib2
import threading
import time


lock = threading.Lock()


def download(url, retvals):
   
    try:
        html = urllib2.urlopen(url).read()
    except urllib2.URLError, exception:
        html = "ERROR: %s" % str(exception)
    lock.acquire()
    retvals.append((url, html))
    lock.release()


def main():
    urls = (
        "http://gerold.bcom.at/",
        "http://halvar.at/",
        "http://lugt.at/",
        "http://microsoft.de/",
        "http://www.python-forum.de/",
        "http://python.org/",
        "http://wallerforum.com/",
        #"http://log-in.fachdid.fu-berlin.de/Archiv/2001/2/Thema/", # braucht zu lange
    )
    retvals = []
    threads = []
    for url in urls:
        threads.append(
            threading.Thread(
                target = download, kwargs = dict(url = url, retvals = retvals)
            )
        )
        threads[-1].start()
        time.sleep(0.2)
   
    # Warten bis alle fertig sind
    for thread in threads:
        thread.join()
       
    for url, html in retvals:
        print url
        if html.startswith("ERROR"):
            print "Achtung Fehler!"
        print html[:100]
        print


if __name__ == "__main__":
    main()

Verfasst: Dienstag 11. Dezember 2007, 14:19
von Rebecca
Keine direkte Antwort auf deine Frage, aber ich verweise mal auf etwas, was ich auch schonmal in einem anderen Thread gesagt habe:
Rebecca hat geschrieben:Multithreading und Multiprocessing ist sinnvoll fuer CPU-lastige nebenlaeufige Programme, fuer IO-lastige Programme aber eventuell nicht optimal. Es gibt noch eine andere Moeglichkeit! Ich zitiere mal die Doku vom asyncore-Modul:
There are only two ways to have a program on a single processor do ``more than one thing at a time.'' Multi-threaded programming is the simplest and most popular way to do it, but there is another very different technique, that lets you have nearly all the advantages of multi-threading, without actually using multiple threads. It's really only practical if your program is largely I/O bound. If your program is processor bound, then pre-emptive scheduled threads are probably what you really need. Network servers are rarely processor bound, however.

If your operating system supports the select() system call in its I/O library (and nearly all do), then you can use it to juggle multiple communication channels at once; doing other work while your I/O is taking place in the ``background.'' Although this strategy can seem strange and complex, especially at first, it is in many ways easier to understand and control than multi-threaded programming. The asyncore module solves many of the difficult problems for you, making the task of building sophisticated high-performance network servers and clients a snap. For ``conversational'' applications and protocols the companion asynchat module is invaluable.

Re: bringen mir threads was ?

Verfasst: Dienstag 11. Dezember 2007, 14:22
von gerold
debian75 hat geschrieben:im moment starte ich gleich viele threads wie ich urls habe
Hallo debian75!

Starte zum Testen einmal die einzelnen HTTP-Anfragen hintereinander und einmal in Threads. Was ist schneller?

Wie ich GIL verstanden habe, kümmert es sich darum, dass sich einzelne Python-Befehle nicht in die Quere kommen können. Ein Befehl wie ``x = 1`` sperrt die Ausführung aller anderen Befehle so lange, bis ``x = 1`` durchgeführt wurde. So kann nicht gleichzeitig ein anderer Thread der Variable x einen anderen Wert zuweisen. Das gilt für einzelne Python-Befehle und nicht für ganze, in Python geschriebene, Funktionen. Diese bestehen ja aus einzelnen Befehlen. Nur die einzelnen Befehle und nicht ganze Funktionen werden geblockt.

mfg
Gerold
:-)

Verfasst: Dienstag 11. Dezember 2007, 14:50
von mitsuhiko
Das GIL darf man nicht überbewerten :-) Ja, du kannst mit Python Threads nicht zwei Prozessorkerne ausnützen, aber das brauchst du auch für dein einfaches Beispiel nicht.

Aber Threads sind insgesamt eine problematische Sache, nicht nur in Python. Man muss immer für jede Aufgabe das richtige Werkzeug nehmen. Und in Python hast du da genug. Threads mit einem Interpreterlock, Grüne Threads (greenlets), und dann kannst du noch forken. Und Parallel Python macht das auch sehr einfach :-)

Verfasst: Dienstag 11. Dezember 2007, 15:39
von debian75
hab da was interessantes gefunden:

http://www.pyzine.com/Issue001/Section_ ... reter.html
In Example #3, we're using the urllib module, which uses blocking sockets under the covers to make HTTP connections. The socket module releases the GIL, so both threads in example 3b can run simultaneously. Therefore, the single-threaded version (3a) is going to run slower in this case.
so wie das ausschaut gibts bei urlopen keinen GIL ? das macht dan threads wieder sinnnvoll für mich. ok, ich kann das zeug nicht gleichzeitig parsen aber immerhin kann ich die daten gleichzeitig holen.

Verfasst: Dienstag 11. Dezember 2007, 15:49
von debian75
da fällt mir gleich noch eine frage ein. wenn urlopen den GIL killt, dann kann ich die html seiten für alles 20 urls gleichzeitig laden.

im moment parse ich die daten auch jeweils im gleichen thread. das heisst aber, dass der thread eben doch blockiert, weil parsen eben wieder GIL anfällig ist.

theoretisch müsste es besser sein, die html daten aus urlopen einfach in ne variable zu schreiben und sonst nichts weiter zu machen im thread.

am schluss, wenn alle threads fertig sind einfach diese eine grosse variable parsen...

sollte doch schneller sein oder ?

Verfasst: Dienstag 11. Dezember 2007, 15:55
von Leonidas
`urlopen` killt da nicht den GIL (wie bist du auf die Formulierung gekommen), sondern es benutzt das `sockets`-Modul, welches in C geschrieben ist. Der GIL betrifft nur Python-Module, keine C-Module.

Verfasst: Dienstag 11. Dezember 2007, 16:03
von BlackJack
@debian75: Auch die Verarbeitung solltest Du in den Threads erledigen. Es können zwar nicht zwei Verarbeitungen wirklich gleichzeitig laufen, aber es kann durchaus etwas verarbeitet werden, solange ein anderer Thread im `socket`-Code steckt. Das Herunterladen wird ja nicht bei allen URLs gleich schnell laufen.

Verfasst: Dienstag 11. Dezember 2007, 16:14
von debian75
Leonidas hat geschrieben:`urlopen` killt da nicht den GIL (wie bist du auf die Formulierung gekommen), sondern es benutzt das `sockets`-Modul, welches in C geschrieben ist. Der GIL betrifft nur Python-Module, keine C-Module.
du musst dir den GIL als "endboss" in nem game vorstellen, der zwischen dir und dem ultimativen "epic" item steht....und das liebe C killt den sack.

Verfasst: Dienstag 11. Dezember 2007, 16:30
von Leonidas
Das "liebe C" killt den GIL nicht, das "liebe C" (und genauer der in C geschriebene Interpreter) aktiviert ihn und deaktiviert ihn ja selbst.

Verfasst: Dienstag 11. Dezember 2007, 16:34
von BlackJack
Der "spawnt" danach aber $GOTT sei Dank wieder. Ohne den gäb's nämlich ganz schönes Chaos.

Verfasst: Dienstag 11. Dezember 2007, 16:43
von debian75
BlackJack hat geschrieben:Der "spawnt" danach aber $GOTT sei Dank wieder. Ohne den gäb's nämlich ganz schönes Chaos.
sie spawnen immer wieder :) ^^