My django app saves django models to a remote database. Sometimes the saves are bursty. In order to free the main thread (*thread_A*) of the application from the time toll of saving multiple objects to the database, I thought of transferring the model objects to a separate thread (*thread_B*) using collections.deque and have *thread_B* save them sequentially.
Yet I’m unsure regarding this scheme. save() returns the id of the new database entry, so it “ends” only after the database responds, which is at the end of the transaction.
Does django.db.models.Model.save() really block GIL-wise and release other python threads during the transaction?
Django’s
save()does nothing special to the GIL. In fact, there is hardly anything you can do with the GIL in Python code — when it is executed, the thread must hold the GIL.There are only two ways the GIL could get released in
save():sys.getcheckinterval()instructions)The second point could be what you are looking for — a SQL
COMMITis executed and during that execution, the SQL backend releases the GIL. However, this depends on the SQL interface, and I’m not sure if the popular ones actually release the GIL*.Moreover,
save()does a lot more than just running a fewUPDATE/INSERTstatements and aCOMMIT; it does a lot of bookkeeping in Python, where it has to hold the GIL. In summary, I’m not sure that you will gain anything from movingsave()to a different thread.UPDATE: From looking at the sources, I learned that both the
sqlitemodule andpsycopgdo release the GIL when they are calling database routines, and I guess that other interfaces do the same.