I'm trying to store data in a global variable inside a Redis Queue (RQ) worker so that this data remains pre-loaded, i.e. it doesn't need to be loaded for every RQ job.
Specifically, I'm working with Word2Vec vectors and loading them using gensim's KeyedVectors.
My app is in Python Flask, running on a Linux server, containerized using Docker.
My goal is to reduce processing time by keeping a handful of large vectors files loaded in memory at all times.
I first tried storing them in global variables in Flask, but then each of my 8 gunicorn workers loads the vectors, which eats up a lot of RAM.
I only need one worker to store a particular vectors file.
I've been told that one solution is to have a set number of RQ workers holding the vectors in a global variable, so that I can control which workers get which vectors files loaded in.
Here is what I have so far:
RQ_worker.py
from rq import Worker, Connection
from gensim.models.keyedvectors import KeyedVectors
from my_common_methods import get_redis
W2V = KeyedVectors.load_word2vec_format('some_path/vectors.bin', binary=True)
def rq_task(some_args):
# use some_args and W2V to do some processing, e.g.:
with open(some_args_filename, 'w') as f_out:
f_out.write(str(W2V['word']))
if __name__ == '__main__':
with Connection(get_redis()):
worker = Worker(['default'])
worker.work()
app.py
from rq import Queue, Connection
from RQ_worker import rq_task
@app.route("/someroute", methods=['POST'])
def some_route():
# test Redis Queue
with Connection(get_redis()):
q = Queue()
task = q.enqueue(rq_task, some_args)
docker-stack.yml
version: '3.7'
services:
nginx:
image: nginx:mainline-alpine
deploy: ...
configs: ...
networks: ...
flask:
image: ...
deploy: ...
environment: ...
networks: ...
volumes: ...
worker:
image: ...
command: python2.7 RQ_worker.py
deploy:
replicas: 1
networks: ...
volumes:
- /some_path/data:/some_path/data
configs:
nginx.conf:
external: true
name: nginx.conf
networks:
external:
external: true
database:
external: true
(I redacted a bunch of stuff from Docker, but can provide more details, if relevant.)
The above generally works, except that the RQ worker seems to load W2V from scratch each time it gets a new job, which defeats the whole purpose. It should keep the vectors stored in W2V as a global variable, so they don't need to be reloaded each time.
Am I missing something? Should I set it up differently?
I've been told that it might be possible to use mmap to load the vectors file into a global variable that the RQ worker sits on, but I'm not sure how that would work with KeyedVectors.
Any advice would be much appreciated!