Uso de múltiples roscados de manera eficiente con millones de solicitudes -- python campo con performance campo con multithreading camp codereview Relacionados El problema

Using multi-threading efficiently with million GET requests


1
vote

problema

Español

Descargo de responsabilidad: La siguiente pregunta no está relacionada con ninguna actividad maliciosa. Sólo las pruebas de rendimiento que estamos haciendo.

Estoy trabajando para consultar un servidor interno con muchas solicitudes (~ 20 millones).
Necesito que sea lo más rápido posible.

Cómo funciona el algoritmo:

  • 30 hilos (porque descubrí que más puede disminuirlo) se están ejecutando en el backgournd y revisando una cola.
  • El Queue contiene una lista de cadenas que estoy generando
  • Cuando un hilo puede ver que la cola no está vacía, tire de una cadena y usa para enviar una solicitud 99887776665544331 al servidor.
  • Si algunos de los subprocesos obtuvieron un código de estado de 200 ellos saldrán, pero mi objetivo es verificar el peor caso , así que en el ejemplo, estoy enviando cadenas que lo harán Haz una mala solicitud ( 404 )

Observe que si envío My Server 20 millones de solicitudes asíncrónicamente, podría bloquearse. Esta es la razón por la que el uso de solo 30 hilos y una cola no bloquean mi servidor.

Diagrama:

ingrese la descripción de la imagen aquí El siguiente es mi código, configuro https://google.com como la URL SOLO PARA UN EJEMPLO, 9988777665544335 Como el número de subprocesos y 9988776655544336 es el tamaño de Solicitudes que estoy enviando: actualmente es solo 100 para probar propósito.
Mi código:

  import time import urllib3 import queue import threading  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) https = urllib3.PoolManager()  # Taken from https://stackoverflow.com/questions/18466079/can-i-change-the-connection-pool-size-for-pythons-requests-module def patch_https_connection_pool(**constructor_kwargs):     """     This allows to override the default parameters of the     HTTPConnectionPool constructor.     For example, to increase the poolsize to fix problems     with "HttpSConnectionPool is full, discarding connection"     call this function with maxsize=16 (or whatever size     you want to give to the connection pool)     """     from urllib3 import connectionpool, poolmanager      class MyHTTPSConnectionPool(connectionpool.HTTPSConnectionPool):         def __init__(self, *args,**kwargs):             kwargs.update(constructor_kwargs)             super(MyHTTPSConnectionPool, self).__init__(*args,**kwargs)     poolmanager.pool_classes_by_scheme['https'] = MyHTTPSConnectionPool   patch_https_connection_pool(maxsize=160)   def try_get_request(some_string):     # I put google.com as an example but it is an internal server     url = 'https://google.com/' + some_string     r = https.request('GET', url, headers={     'Content-Type': 'application/json'     })      return r.status  def queue_algo():     NUM_CONCURRENT_REQUESTS = 30     work = queue.Queue()     global end_process     end_process = False      def worker():         global end_process         #print('****** TID %s: STARTED ******' % threading.get_ident())         while not end_process:             try:                 some_string = work.get(True, 3)                 #print("TID %s: Testing %s" % (threading.get_ident(), some_string))                 status = try_get_request(some_string)                 #print("TID %s: DONE %s" % (threading.get_ident(), some_string))                 if status == 200:                     print('found 200 status code')                     end_process = True                     work.task_done()                 else:                     continue             except queue.Empty:                 continue              work.task_done()      threads = []     for unused_index in range(NUM_CONCURRENT_REQUESTS):         thread = threading.Thread(target=worker)         thread.daemon = True         thread.start()         threads.append(thread)      queued = 0     wait = False      try:         # The strings I am sending         size = 100         for i in range(0, size):             work.put(str(i))             queued += 1             if queued >= size:                 wait = True                 break         if wait:             while work.qsize() > 0:                 time.sleep(5)             end_process = True             for thread in threads:                 if thread.is_alive():                     thread.join()      except KeyboardInterrupt:         end_process = True         for thread in threads:             if thread.is_alive():                 thread.join()  start_time = time.time() queue_algo() print("--- %s seconds ---" % (time.time() - start_time))   

Lo escribí en Python y me han dicho que esta no es la mejor solución para usar hilos.
También lo intenté con Go tampoco no tengo un ejemplo del código.
Las estadísticas actuales en mi servidor interno son 100,000 solicitudes con 30 hilos en 2.6 minutos.
Esto es demasiado, necesito hacerlo mucho más rápido.
Debido a que no puedo compartir con usted, mi servidor interno, pongo https://google.com como ejemplo para la URL que puede probarlo para verificar los tiempos.

¡Quería saber cómo sugieres abordarlo? Tal vez la arquitectura de usar hilos con cola no sea la mejor y hay una mejor. Tal vez Python no es el idioma para tales cosas debido al mecanismo de Gil que los hilos no funcionan como hilos "reales".

Original en ingles

Disclaimer: The following question is not related to any malicious activity. Only performance testing we are doing.

I am working on querying an internal server with lots of requests (~20 million).
I need it to be as fast as possible.

How the algorithm works:

  • 30 Threads (because I found that more can slow it down) are running in the backgournd and checking a Queue.
  • The Queue contains a list of strings that I am generating
  • When a thread see that the Queue is not empty, it pull a string and using to send a GET request to the server.
  • If some of the threads got a status code of 200 they will exit but my goal is to check the WORST CASE so in the example I am sending strings that will make a bad request (404)

Notice that if I send my server 20 million requests asynchronically it might crash. This is why the use of only 30 threads and a Queue doesn't crash my server.

Diagram:

enter image description here The following is my code, I set https://google.com as the URL just for an example, NUM_CONCURRENT_REQUESTS = 30 as the number of threads and size = 100 is the size of requests I am sending - currently it just 100 for testing purpose.
My Code:

import time import urllib3 import queue import threading  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) https = urllib3.PoolManager()  # Taken from https://stackoverflow.com/questions/18466079/can-i-change-the-connection-pool-size-for-pythons-requests-module def patch_https_connection_pool(**constructor_kwargs):     """     This allows to override the default parameters of the     HTTPConnectionPool constructor.     For example, to increase the poolsize to fix problems     with "HttpSConnectionPool is full, discarding connection"     call this function with maxsize=16 (or whatever size     you want to give to the connection pool)     """     from urllib3 import connectionpool, poolmanager      class MyHTTPSConnectionPool(connectionpool.HTTPSConnectionPool):         def __init__(self, *args,**kwargs):             kwargs.update(constructor_kwargs)             super(MyHTTPSConnectionPool, self).__init__(*args,**kwargs)     poolmanager.pool_classes_by_scheme['https'] = MyHTTPSConnectionPool   patch_https_connection_pool(maxsize=160)   def try_get_request(some_string):     # I put google.com as an example but it is an internal server     url = 'https://google.com/' + some_string     r = https.request('GET', url, headers={     'Content-Type': 'application/json'     })      return r.status  def queue_algo():     NUM_CONCURRENT_REQUESTS = 30     work = queue.Queue()     global end_process     end_process = False      def worker():         global end_process         #print('****** TID %s: STARTED ******' % threading.get_ident())         while not end_process:             try:                 some_string = work.get(True, 3)                 #print("TID %s: Testing %s" % (threading.get_ident(), some_string))                 status = try_get_request(some_string)                 #print("TID %s: DONE %s" % (threading.get_ident(), some_string))                 if status == 200:                     print('found 200 status code')                     end_process = True                     work.task_done()                 else:                     continue             except queue.Empty:                 continue              work.task_done()      threads = []     for unused_index in range(NUM_CONCURRENT_REQUESTS):         thread = threading.Thread(target=worker)         thread.daemon = True         thread.start()         threads.append(thread)      queued = 0     wait = False      try:         # The strings I am sending         size = 100         for i in range(0, size):             work.put(str(i))             queued += 1             if queued >= size:                 wait = True                 break         if wait:             while work.qsize() > 0:                 time.sleep(5)             end_process = True             for thread in threads:                 if thread.is_alive():                     thread.join()      except KeyboardInterrupt:         end_process = True         for thread in threads:             if thread.is_alive():                 thread.join()  start_time = time.time() queue_algo() print("--- %s seconds ---" % (time.time() - start_time)) 

I wrote it in Python and I have been told that this is not the best solution for using threads.
I also tried with Go also I don't have here an example of the code.
The current stats on my internal server are 100,000 requests with 30 threads in 2.6 minutes.
This is too much, I need to do it much faster.
Because I can't share with you my internal server I put https://google.com as an example for URL that can test it to check the times.

I wanted to know how you suggest to approach it ? Maybe the architecture of using threads with Queue is not the best and there is a better one. Maybe Python is not the language for such stuff because of the GIL mechanism that threads are not working as a "real" threads.

        

Lista de respuestas


Relacionados problema

2  Programa de productores / consumidores  ( Producer consumer program ) 
Soy un programador de Java semi-nuevo que tiende a ser un perfeccionista. Lo que me gustaría saber sobre mi código: cómo se compara con la práctica común. ...

8  Prueba de registro multithread  ( Multithreaded log test ) 
Estoy escribiendo una extensión de registrador que permite que varios subprocesos registren un proceso, y luego voltee ese registro en el registro principal e...

2  Prealización de memoria multi-roscada  ( Multi threaded memory preallocation ) 
Necesito averiguar la mejor manera de lidiar con la asignación previa a la memoria A continuación se muestra el pseudo-código para lo que estoy haciendo aho...

5  Alcanzar un objeto grande en el entorno multithreading  ( Caching large object in multithreading environment ) 
Estoy teniendo que desbordarse con el almacenamiento en caché y el multithreading (hilo por solicitud), y soy un principiante absoluto en esa área, por lo que...

4  Conexión a la red Haskell Handler agraciado  ( Haskell network connection graceful handler ) 
Simplemente tratando de resolver un simple código de manejo de conexiones elegante en Haskell para obtener la cabeza alrededor de algunas de las cosas de IO /...

4  Programador de tareas de flujo  ( Flow task scheduler ) 
escenario : Quería un programador de tareas / Duende que permite que mi aplicación programe algunas tareas que se ejecuten en un tiempo específico pero e...

3  Generador de imágenes de Mandelbrot con iteración paralela  ( Mandelbrot image generator with parallel iteration ) 
Actualmente estoy tratando de optimizar esta clase que tengo para la generación fractal. La ecuación está destinada a ser conectable; He usado z => z*z + c ...

5  Contando letras lo más rápido posible  ( Counting letters as quickly as possible ) 
Recibí una tarea, de tomar un archivo de texto conocido (Diccionario de Linux), use hilos para contar las diferentes letras en ella y presentar los resultados...

6  Un pequeño módulo para manejar actualizaciones de texto  ( A tiny module for handling text updates ) 
Llame a estas actualizaciones de texto "Feeds". Un objeto Feed tiene algunos atributos básicos como su cadena de contenido, cuántas vidas tiene y su priorid...

2  Cola de bloqueo delimitada  ( Bounded blocking queue ) 
¿Puede alguien por favor revise este código para mí? No he implementado todos los métodos para la simplicidad. NSUSerDefaults1 Preguntas abiertas: l...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos