2016-03-24 13 views
-1

Meine Anwendung verwendet mehrere E/A-Blockierung (Netzwerk) Anforderungen, die eine Weile dauern, um abzuschließen. Ich habe versucht, Multi Threading zu verwenden, aber es scheint keine Beschleunigung zu bringen, ich vermute, es hat etwas mit Pythons GIL zu tun.Python Multi Threading mit blockierenden E/A

Die Sache ist, dass alle Anfragen gleichzeitig erledigt werden können und keine Abhängigkeiten voneinander haben. Wie löse ich dieses Leistungsproblem?

Mein Code

import threading 
import urllib2 
import time 
def send_request(url, count_str): 
    start_time = time.time() 
    urllib2.urlopen(url) 
    print "Request " + count_str + " took " + str(time.time() - start_time) + " started at " + str(start_time) 

count = 0 
for url in open('urllist.txt'): 
    t = threading.Thread(target=send_request, args = (url.strip(), str(count))) 
    t.start() 
    count+=1 

Der Ausgang ist

Request 1 took 5.0150949955 started at 1458789266.78 
Request 2 took 10.0112490654 started at 1458789266.79 
Request 0 took 15.024559021 started at 1458789266.78 
Request 3 took 20.016972065 started at 1458789266.79 

Die Urls in urllist.txt Punkt auf einem Server ich lokal ausgeführt werde, dass 5 Sekunden dauern, zu reagieren. Wie Sie sehen können, "starten" alle zur gleichen Zeit, aber sie blockieren.

+0

Sie können uns Ihren Code zeigen :) – Signal

+0

@Signal aktualisiert it =) Ich bin sehr neu in Multithreading in Python so könnte ziemlich viel falsch damit sein –

+0

Wie soll 'q.join()' zurückgeben? Nichts in Ihrem Code verarbeitet die 'Queue' zum Aufruf von' .get() 'geschweige denn' .task_done() '. Du gibst auch nichts von 'get_and_read_url' zurück, also gibst du nur 'None' in die Warteschlange. Abschließend möchte ich noch folgendes anmerken: Für das Threading im Allgemeinen und insbesondere für die Warteschlangen ist Python 2 _bad_; Wenn Sie zu neuerem Python wechseln können ([3.2 oder später] (https://docs.python.org/3/whatsnew/3.2.html#multi-threading)), bedeutet das umgeschriebene GIL, dass Sie beim Threading nichts gewinnen Bei CPU-gebundenen Tasks läuft es nicht wesentlich langsamer und verbraucht nur GIL-Overhead. – ShadowRanger

Antwort

1

Ich kann Ihr Problem nicht reproduzieren (beim Testen gegen eine Handvoll Internet-Server, jeder wiederholt ein paar Mal, alle Anfragen werden in etwa zur gleichen Zeit gewartet, keine stetig steigenden Verzögerungen), aber Ihre neue Ausgabe zeigt auf eine vollständig anderes Problem: Ich vermute, dass der "lokale Server", den Sie verwenden, möglicherweise nicht Multithread ist (oder anderweitig in der Lage ist, mehrere Anfragen gleichzeitig zu bearbeiten).

Ihre eigene Ausgabe zeigt an, dass die Threads parallel gestartet werden, aber Anfragen seriell bearbeitet werden; Wenn es GIL-Handoff-Probleme waren, würde ich erwarten, dass alle etwas verzögert wären (ein Thread würde etwas Arbeit erledigen, dann würde ein anderes mehr tun, etc.), und nicht jedes bis zum Abschluss vor dem nächsten Start . Dies führt zu einem Problem auf der Serverseite, bei der der Server Anforderungen bis zum Abschluss behandelt, bevor zusätzliche Verbindungen ausgeführt werden.

Nehmen Sie einen Stich bei psychischen Debugging, haben Sie die fünf Sekunden Anfrage Zeit durch Hinzufügen eines Schlafes im Server-Code, möglicherweise nach accept kehrt zurück, aber vor dem Start eines Threads, um es zu bedienen? Oder verwenden Sie Threading überhaupt nicht auf dem Server?

+0

Wow das war es.Der lokale Server, den ich ausgeführt habe, hatte kein Multithreading aktiviert und blockierte in der Antwort. Sollte ich die Frage schließen oder zumindest umbenennen, weil es kein Python-Problem ist und tatsächlich ein Problem beim Testen der Leistung aufgetreten ist? –

+0

@tt_Gantz: Ich würde es nicht schließen, da es in seinem aktuellen Zustand tatsächlich eine Frage stellt, die jemand aus den gleichen Gründen in Zukunft legitim stellen könnte, und es gibt (jetzt) ​​genug Informationen, um ihnen zu helfen, ihre zu identifizieren eigenes Problem. – ShadowRanger

-1

Python-Threads sind langsam! Python hat eine GIL (Global Interpreter Lock), die einen Mutex verwendet, um den Zugriff auf Interna zu serialisieren. Vielleicht möchten Sie sich Jython anschauen, das keine GIL besitzt und Multiprozessorsysteme voll ausnutzen kann.

+0

Das OP ist sich der GIL bewusst, die es in der Frage erwähnt hat; Die Threads sollten jedoch E/A-gebunden sein, und das Threading zum Koordinieren von parallelen Tasks, die E/A blockieren, ist in der Regel in Ordnung. "Die GIL ist schlecht, also benutze niemals Threads" ist eine enorme Vereinfachung und fügt nichts hinzu. Und angesichts der schrecklichen Unterstützung von Jython (mehr als fünf Jahre hinter der Sprachspezifikation) wäre das nicht meine erste Empfehlung. – ShadowRanger