Tak więc próbuję wielu wątków niektórych połączeń internetowych w python. Używałem modułu do przetwarzania wieloprocesowego, dzięki czemu mogę poruszać się po "Global Interpreter Lock". Ale wydaje się, że system daje tylko jeden port otwartego połączenia pythonowi, a przynajmniej pozwala tylko na jedno połączenie na raz. Oto przykład tego, co mówię.Ile portów sieciowych obsługuje Python?
* Należy pamiętać, że jest uruchomiony na serwerze linux
from multiprocessing import Process, Queue
import urllib
import random
# Generate 10,000 random urls to test and put them in the queue
queue = Queue()
for each in range(10000):
rand_num = random.randint(1000,10000)
url = ('http://www.' + str(rand_num) + '.com')
queue.put(url)
# Main funtion for checking to see if generated url is active
def check(q):
while True:
try:
url = q.get(False)
try:
request = urllib.urlopen(url)
del request
print url + ' is an active url!'
except:
print url + ' is not an active url!'
except:
if q.empty():
break
# Then start all the threads (50)
for thread in range(50):
task = Process(target=check, args=(queue,))
task.start()
Więc jeśli uruchomić to można zauważyć, że rozpoczyna się 50 wystąpień na temat funkcji, ale działa tylko jeden na raz. Możesz myśleć, że "Global Interpreter Lock" to robi, ale tak nie jest. Spróbuj zmienić funkcję na funkcję matematyczną zamiast na żądanie sieciowe, a zobaczysz, że wszystkie pięćdziesiąt wątków jest uruchamianych jednocześnie.
Czy będę musiał pracować z gniazdkami? Czy jest coś, co mogę zrobić, aby uzyskać dostęp Pythona do większej liczby portów? Czy jest coś, czego nie widzę? Powiedz mi co myślisz! Dzięki!
* Edycja
Więc napisałem ten skrypt, aby przetestować rzeczy lepiej z biblioteką żądań. Wygląda na to, że wcześniej nie testowałem tego zbyt dobrze. (Używałem głównie urllib i urllib2)
from multiprocessing import Process, Queue
from threading import Thread
from Queue import Queue as Q
import requests
import time
# A main timestamp
main_time = time.time()
# Generate 100 urls to test and put them in the queue
queue = Queue()
for each in range(100):
url = ('http://www.' + str(each) + '.com')
queue.put(url)
# Timer queue
time_queue = Queue()
# Main funtion for checking to see if generated url is active
def check(q, t_q): # args are queue and time_queue
while True:
try:
url = q.get(False)
# Make a timestamp
t = time.time()
try:
request = requests.head(url, timeout=5)
t = time.time() - t
t_q.put(t)
del request
except:
t = time.time() - t
t_q.put(t)
except:
break
# Then start all the threads (20)
thread_list = []
for thread in range(20):
task = Process(target=check, args=(queue, time_queue))
task.start()
thread_list.append(task)
# Join all the threads so the main process don't quit
for each in thread_list:
each.join()
main_time_end = time.time()
# Put the timerQueue into a list to get the average
time_queue_list = []
while True:
try:
time_queue_list.append(time_queue.get(False))
except:
break
# Results of the time
average_response = sum(time_queue_list)/float(len(time_queue_list))
total_time = main_time_end - main_time
line = "Multiprocessing: Average response time: %s sec. -- Total time: %s sec." % (average_response, total_time)
print line
# A main timestamp
main_time = time.time()
# Generate 100 urls to test and put them in the queue
queue = Q()
for each in range(100):
url = ('http://www.' + str(each) + '.com')
queue.put(url)
# Timer queue
time_queue = Queue()
# Main funtion for checking to see if generated url is active
def check(q, t_q): # args are queue and time_queue
while True:
try:
url = q.get(False)
# Make a timestamp
t = time.time()
try:
request = requests.head(url, timeout=5)
t = time.time() - t
t_q.put(t)
del request
except:
t = time.time() - t
t_q.put(t)
except:
break
# Then start all the threads (20)
thread_list = []
for thread in range(20):
task = Thread(target=check, args=(queue, time_queue))
task.start()
thread_list.append(task)
# Join all the threads so the main process don't quit
for each in thread_list:
each.join()
main_time_end = time.time()
# Put the timerQueue into a list to get the average
time_queue_list = []
while True:
try:
time_queue_list.append(time_queue.get(False))
except:
break
# Results of the time
average_response = sum(time_queue_list)/float(len(time_queue_list))
total_time = main_time_end - main_time
line = "Standard Threading: Average response time: %s sec. -- Total time: %s sec." % (average_response, total_time)
print line
# Do the same thing all over again but this time do each url at a time
# A main timestamp
main_time = time.time()
# Generate 100 urls and test them
timer_list = []
for each in range(100):
url = ('http://www.' + str(each) + '.com')
t = time.time()
try:
request = requests.head(url, timeout=5)
timer_list.append(time.time() - t)
except:
timer_list.append(time.time() - t)
main_time_end = time.time()
# Results of the time
average_response = sum(timer_list)/float(len(timer_list))
total_time = main_time_end - main_time
line = "Not using threads: Average response time: %s sec. -- Total time: %s sec." % (average_response, total_time)
print line
Jak widać, jest bardzo wielowątkowy. W rzeczywistości większość moich testów pokazuje, że moduł wątkowania jest rzeczywiście szybszy niż moduł wieloprocesowy. (Nie rozumiem dlaczego!) Oto niektóre z moich wyników.
Multiprocessing: Average response time: 2.40511314869 sec. -- Total time: 25.6876308918 sec.
Standard Threading: Average response time: 2.2179402256 sec. -- Total time: 24.2941861153 sec.
Not using threads: Average response time: 2.1740363431 sec. -- Total time: 217.404567957 sec.
Dokonano tego w mojej sieci domowej, czas reakcji na moim serwerze jest znacznie szybszy. Myślę, że moje pytanie zostało udzielone pośrednio, ponieważ miałem problemy z dużo bardziej złożonym scenariuszem. Wszystkie sugestie pomogły mi ją zoptymalizować. Dziękuję wszystkim!
Czy próbowałeś inny moduł Pythona do robi legwork HTTP, może [żądania] (http: //docs.python -requests.org/en/latest/)? Znamy 'urllib' [nie jest wątkiem bezpiecznym] (http://stackoverflow.com/a/5825531/228489), chociaż nie sądzę, że powinno to wpływać na proces wieloprocesowy, ale spróbuję użyć innego modułu, aby znaleźć na zewnątrz. – amccormack
Jak rozpoznać, że działa tylko jeden proces? Wydaje mi się, że funkcja matematyczna jest znacznie szybsza do wykonania niż żądanie http i chociaż może się wydawać, że bieg jest synchroniczny, to faktycznie wykonuje wiele żądań, ale udaje mu się wyraźnie napisać na standardowe wyjście, ponieważ są one wolne. –
@ReutSharabani Cóż, sprawdzałem to na "htop", ale również wypisuje tylko jeden na raz. Jeśli faktycznie uruchomił wiele procesów, wydrukowałby wiele na raz. – TysonU