2017-09-16 5 views
1

versuchen für 2 Tage Multi-Processing zum Arbeiten beim Erstellen von Verbindungen zu einem NNTP-Server. Ziel: Mach so schnell wie möglich eine Menge Verbindungen (wie 50). Da das Herstellen von Verbindungen in einer for-Schleife langsam sein kann (z. B. bis zu 10 s), möchte ich sie alle gleichzeitig mit Multiprocessing machen. Nach dem Erstellen der Verbindungen bleiben sie offen, da in einem zukünftigen Multiprocessing-Teil mehr als 10.000 Anfragen gestellt werden, die sich auf ein ähnliches Prinzip stützen.So erstellen Sie Nntplib-Objekte mit Multiprocessing

Einige vereinfachte Teil des Codes:

#!/usr/bin/env python3 

import sys 
import ssl 
from nntplib import NNTP_SSL 
from multiprocessing import Pool 

def MakeCon(i, host, port): 
    context = ssl.SSLContext(ssl.PROTOCOL_TLS) 
    s = NNTP_SSL(host, port=port, ssl_context=context, readermode=True) 
    print('created connection', i) # print to see progress 
    sys.stdout.flush() 
    return s 

def Main(): 
    host = 'reader.xsnews.nl' 
    port = 563 
    num_con = 4 

    y=MakeCon(1, host, port).getwelcome() #request some message from NNTP host to see if it works 
    print(y) 

    # the actual part that has the issue: 
    if __name__ == '__main__': 

     cons = range(num_con) 
     s = [None] * num_con 
     pool = Pool() 
     for con in cons: 
      s[con]=pool.apply_async(MakeCon, args=(con, host, port)) 
     pool.close 

     print(s[1]) 
     for con in cons: 
      t=s[con].getwelcome() #request some message from NNTP host to see if it works 
      print(t) 

     print('end') 

Main() 

angezeigt, dass die Verbindung zum NNTP-Server usw. funktioniert, aber ich kann nicht an dem Teil der Verbindungen in ein Objekt zu extrahieren I in Kombination mit dem nntplib verwenden kann Optionen. Ich würde sagen, ich bin nicht so erfahren mit Python, vor allem nicht Multiprocessing.

+0

Versuchen Sie, mehrere Verbindungen zu demselben Newsserver zu erstellen? – JohanL

+0

@JohanL Danke, ja, und so schnell wie möglich, also ich mag es nicht, Schleife über die NNTP_SSL()/NNTP(), wie jedes Mal es eine Wartezeit von sagen kann 1 s, bevor die Verbindung hergestellt wird. Deshalb möchte ich sie 'simultan' mit Multiprocessing erstellen. – uytda

Antwort

1

Es gibt ein paar verschiedene Probleme mit Ihrem Ansatz. Die größte ist, dass es nicht funktioniert, die Verbindung in verschiedenen Prozessen zu erstellen und sie dann an den Hauptprozess zu senden. Dies liegt daran, dass jede Verbindung einen Socket öffnet und Sockets nicht serialisierbar (auswählbar) sind und daher nicht zwischen Prozessen gesendet werden können.

Und auch wenn es funktioniert hat, ist die Verwendung von .apply_sync() nicht der richtige Weg. Es ist besser, .map() zu verwenden, das direkt die Ausgabe des Funktionsaufrufs zurückgibt (im Gegensatz zu .apply_sync(), das ein Objekt zurückgibt, von dem der Rückgabewert extrahiert werden kann).

In der aktuellen Situation ist das Programm jedoch E/A-gebunden, anstatt CPU-gebunden, und in diesen Situationen funktioniert Threading genauso gut wie Multiprozessing, da die GIL die Ausführung nicht zurückhält. Statt also Multiprozessing auf Threads zu ändern und zu .map() von .apply_sync() gibt die folgende Lösung:

#!/usr/bin/env python3 

import sys 
import ssl 
from nntplib import NNTP_SSL 
from multiprocessing.pool import ThreadPool 

def MakeCon(i, host, port): 
    context = ssl.SSLContext(ssl.PROTOCOL_TLS) 
    s = NNTP_SSL(host, port=port, ssl_context=context, readermode=True) 
    print('created connection', i) # print to see progress 
    sys.stdout.flush() 
    return s 

def Main(): 
    host = 'reader.xsnews.nl' 
    port = 563 
    num_con = 4 

    y=MakeCon(1, host, port).getwelcome() #request some message from NNTP host to see if it works 
    print(y) 
    return con 

    cons = range(num_con) 
    s = [None] * num_con 
    pool = ThreadPool() 
    s=pool.map(lambda con: MakeCon(con, host, port), cons) 
    pool.close 

if __name__ == "__main__": 
    Main() 

Ein kleines Wort der Beratung, though. Seien Sie vorsichtig bei der Erstellung von zu vielen Verbindungen, da dies vom Server nicht gut dargestellt wird, da Sie dadurch Ressourcen entlasten.

Wenn Sie Ihre verschiedenen Verbindungen verwenden, um Artikel abzurufen, sollten diese Aufrufe wahrscheinlich auch in anderen Threads ausgeführt werden.

Und als letzter Kommentar, den gleichen Effekt wie die Verwendung von Threads ist asyncio zu verwenden. Das ist jedoch etwas, das Sie wahrscheinlich eine Weile studieren müssen, bevor Sie sich wohl fühlen.

+0

Die Steckdosen funktionieren gut und viel schneller. Ich benutzte das gleiche Prinzip für die erstellten Sockets, um Header über die Funktion 'check_id()' anzufordern, um die Loop-Liste 'ids' zu füllen:' j = itertools.cycle (Bereich (len (socks))) 'gefolgt von' t = pool. map (lambda id: check_id (socks, next (j), id), ids) Dieser Ansatz wird für 4 Sockets etwas schneller als für 1, aber für 10 gibt es keinen Gewinn. (Ping und Latenz sind sehr niedrig für den Server). Raten Sie, dass die Zyklusmethode es anhält, da ein typischer Sockel noch nicht frei ist. (vorher habe ich 'socket' i/o' nntplib' benutzt, und viel loop gemacht, um 'asyncio' zu vermeiden) – uytda

Verwandte Themen