with tutorial fetchmany error descargar python sqlite

tutorial - sqlite3 python install



Python sqlite3 y concurrencia (13)

Tengo un programa Python que usa el módulo "threading". Una vez por segundo, mi programa inicia un nuevo hilo que recupera algunos datos de la web y almacena estos datos en mi disco duro. Me gustaría usar sqlite3 para almacenar estos resultados, pero no puedo hacer que funcione. El problema parece ser sobre la siguiente línea:

conn = sqlite3.connect("mydatabase.db")

  • Si pongo esta línea de código dentro de cada hilo, obtengo un OperationalError que me dice que el archivo de la base de datos está bloqueado. Supongo que esto significa que otro hilo tiene mydatabase.db abierto a través de una conexión sqlite3 y lo ha bloqueado.
  • Si pongo esta línea de código en el programa principal y paso el objeto de conexión (conn) a cada hilo, obtengo un ProgrammingError, diciendo que los objetos SQLite creados en un hilo solo pueden usarse en ese mismo hilo.

Anteriormente estaba almacenando todos mis resultados en archivos CSV y no tenía ninguno de estos problemas de bloqueo de archivos. Espero que esto sea posible con sqlite. ¿Algunas ideas?


Cambiar a multiprocessing . Es mucho mejor, se escala bien, puede ir más allá del uso de múltiples núcleos mediante el uso de varias CPU, y la interfaz es la misma que usar el módulo de subprocesamiento de python.

O, como Ali sugirió, simplemente use el mecanismo de agrupamiento de hilos de SQLAlchemy . Se encargará de todo automáticamente y tiene muchas características adicionales, solo para citar algunas de ellas:

  1. SQLAlchemy incluye dialectos para SQLite, Postgres, MySQL, Oracle, MS-SQL, Firebird, MaxDB, MS Access, Sybase e Informix; IBM también ha lanzado un controlador de DB2. De modo que no tiene que volver a escribir su aplicación si decide alejarse de SQLite.
  2. El sistema Unit Of Work, una parte central del Object Relational Mapper (ORM) de SQLAlchemy, organiza las operaciones pendientes de crear / insertar / actualizar / eliminar en colas y las vacía en un solo lote. Para lograr esto, realiza una "clasificación de dependencia" topológica de todos los elementos modificados en la cola para cumplir con las restricciones de clave externa, y agrupa las declaraciones redundantes juntas donde a veces se pueden agrupar aún más. Esto produce la eficiencia máxima y la seguridad de las transacciones, y minimiza las posibilidades de interbloqueos.

Contrario a la creencia popular, las versiones más nuevas de sqlite3 admiten el acceso desde múltiples hilos.

Esto se puede habilitar mediante el argumento de palabra clave opcional check_same_thread :

sqlite.connect(":memory:", check_same_thread=False)


La razón más probable por la que obtiene errores con bases de datos bloqueadas es que debe emitir

conn.commit()

después de terminar una operación de base de datos. Si no lo hace, su base de datos será bloqueada por escritura y permanecerá así. Los otros subprocesos que están esperando para escribir se agotarán después de un tiempo (el valor predeterminado se establece en 5 segundos; consulte http://docs.python.org/2/library/sqlite3.html#sqlite3.connect para obtener detalles sobre eso) .

Un ejemplo de inserción correcta y concurrente sería este:

import threading, sqlite3 class InsertionThread(threading.Thread): def __init__(self, number): super(InsertionThread, self).__init__() self.number = number def run(self): conn = sqlite3.connect(''yourdb.db'', timeout=5) conn.execute(''CREATE TABLE IF NOT EXISTS threadcount (threadnum, count);'') conn.commit() for i in range(1000): conn.execute("INSERT INTO threadcount VALUES (?, ?);", (self.number, i)) conn.commit() # create as many of these as you wish # but be careful to set the timeout value appropriately: thread switching in # python takes some time for i in range(2): t = InsertionThread(i) t.start()

Si le gusta SQLite, o tiene otras herramientas que funcionan con bases de datos SQLite, o desea reemplazar archivos CSV con archivos db SQLite, o debe hacer algo raro como IPC interplataforma, entonces SQLite es una gran herramienta y muy adecuada para este propósito. ¡No se deje presionar para que use una solución diferente si no se siente bien!


Lo siguiente se encuentra en mail.python.org.pipermail.1239789

He encontrado la solución. No sé por qué la documentación de Python no tiene ni una sola palabra sobre esta opción. Entonces, tenemos que agregar un nuevo argumento de palabra clave a la función de conexión y podremos crear cursores en un hilo diferente. Entonces usa:

sqlite.connect(":memory:", check_same_thread = False)

funciona a la perfección para mí. Por supuesto, a partir de ahora tengo que ocuparme del acceso seguro a subprocesos a la base de datos. De todos modos, todo por tratar de ayudar.


Me gusta la respuesta de Evgeny: las colas generalmente son la mejor forma de implementar la comunicación entre hilos. Para completar, estas son algunas otras opciones:

  • Cierre la conexión DB cuando los subprocesos generados hayan terminado de usarlo. Esto arreglaría su OperationalError , pero abrir y cerrar conexiones como esta generalmente es un No-No, debido a la sobrecarga del rendimiento.
  • No use hilos secundarios. Si la tarea de una vez por segundo es razonablemente liviana, puede salirse con la tarea de buscar y almacenar, y luego dormir hasta el momento adecuado. Esto es indeseable ya que las operaciones de búsqueda y almacenamiento pueden llevar> 1 segundo y usted pierde el beneficio de los recursos multiplexados que tiene con un enfoque de múltiples subprocesos.

Me gustaría echar un vistazo al módulo Python y_serial para la persistencia de los datos: http://yserial.sourceforge.net

que maneja problemas de interbloqueo que rodean una única base de datos SQLite. Si la demanda de concurrencia se hace más pesada, se puede configurar fácilmente la clase Farm de muchas bases de datos para difundir la carga sobre el tiempo estocástico.

Espero que esto ayude a su proyecto ... debería ser lo suficientemente simple como para implementarlo en 10 minutos.


Necesita diseñar la concurrencia para su programa. SQLite tiene limitaciones claras y debe obedecerlas, consulte las FAQ (también la siguiente pregunta).


No deberías utilizar hilos para nada. Esta es una tarea trivial para twisted y eso te llevaría significativamente más lejos de todos modos.

Use solo un hilo, y haga que la finalización de la solicitud active un evento para hacer la escritura.

twisted se encargará de la programación, devolución de llamadas, etc ... para ti. Te entregará el resultado completo como una cadena, o puedes ejecutarlo a través de un procesador de flujo (tengo una API de Twitter y una API friendfeed que disparan eventos a las personas que llaman ya que los resultados aún se están descargando).

Dependiendo de lo que esté haciendo con sus datos, puede simplemente volcar el resultado completo en sqlite cuando esté completo, cocinarlo y volcarlo, o cocinarlo mientras se está leyendo y volcarlo al final.

Tengo una aplicación muy simple que hace algo parecido a lo que quieres en github. Yo lo llamo pfetch (búsqueda paralela). Captura varias páginas en un cronograma, transmite los resultados a un archivo y, opcionalmente, ejecuta un guión al completar con éxito cada uno. También hace cosas sofisticadas como GET condicional, pero aún así podría ser una buena base para lo que sea que estés haciendo.


No pude encontrar ningún punto de referencia en ninguna de las respuestas anteriores, así que escribí una prueba para comparar todo.

Intenté 3 enfoques

  1. Lectura y escritura secuencialmente desde la base de datos SQLite
  2. Usar un ThreadPoolExecutor para leer / escribir
  3. Usar un ProcessPoolExecutor para leer / escribir

Los resultados y conclusiones del benchmark son los siguientes

  1. Las lecturas secuenciales / escrituras secuenciales funcionan de la mejor manera
  2. Si debe procesar en paralelo, use ProcessPoolExecutor para leer en paralelo
  3. No realice ninguna escritura usando ThreadPoolExecutor o usando ProcessPoolExecutor ya que se encontrará con errores bloqueados en la base de datos y tendrá que volver a intentar insertar el fragmento nuevamente

Puede encontrar el código y completar la solución para los puntos de referencia en mi respuesta SO HERE Espero que ayude!


O si eres perezoso, como yo, puedes usar SQLAlchemy . Manejará el subproceso por usted, ( utilizando subprocesos locales y algunos grupos de conexiones ) y la forma en que lo hace es incluso configurable .

Para una ventaja adicional, si / cuando te das cuenta / decides que usar Sqlite para cualquier aplicación simultánea será un desastre, no tendrás que cambiar tu código para usar MySQL, Postgres o cualquier otra cosa. Usted puede simplemente cambiar.


Puede usar el patrón de productor consumidor. Por ejemplo, puede crear una cola que se comparte entre hilos. El primer hilo que recupera datos de la web pone en cola estos datos en la cola compartida. Otro hilo que posee conexión de base de datos dequeue datos de la cola y los pasa a la base de datos.



Scrapy parece una posible respuesta a mi pregunta. Su página de inicio describe mi tarea exacta. (Aunque no estoy seguro de cuán estable es el código todavía).