redis-py icon indicating copy to clipboard operation
redis-py copied to clipboard

redis.hgetall() Python multithreading is not executing concurrently with multiple redis servers

Open AkashBera opened this issue 1 year ago • 1 comments

Redis Server version - 7.0.11 (latest)

Description: Running multiple Redis standalone servers (ports: 7000, 7002, 7004). Using multi-threading to read from multiple servers concurrently. Hence, number of threads = 3.

Issue - Python's avg time for hgetall(key) using 3 threads = 3 * avg time for the single thread execution.

With Java, it's working as expected. With below benchmark code and output, it's visible that python avg time (for hgetall(key)) = 90ms and java avg time(for hgetall(key)) = 28 ms for the same key with 3 threads(for 3 server concurrent read)

Java - jedis verson - 4.4.1

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Arrays;
import static java.lang.System.nanoTime;

class ThreadedRedisRead implements Runnable {

    int port;

    public ThreadedRedisRead(int port) {
        this.port = port;
    }

    public void run() {
        System.out.println("thread is running...");
        JedisPool pool = new JedisPool("localhost", port);

        int numOfIterations = 100;
        long[] res = new long[numOfIterations];
        for (int i = 0; i < numOfIterations; i++) {
            try (Jedis jedis = pool.getResource()) {
                res[i] = read_data(jedis);
            }

        }

        System.out.println("avg = " + Arrays.stream(res).sum() / numOfIterations);
        System.out.println("max = " + Arrays.stream(res).max().getAsLong());
        System.out.println("min = " + Arrays.stream(res).min().getAsLong());

        // Prints: {name=John, surname=Smith, company=Redis, age=29}

    }

    public static long read_data(Jedis jedis) {
        long start = nanoTime();
        jedis.hgetAll("seller-1");
        return (nanoTime() - start) / 1000000;
    }

}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(new ThreadedRedisRead(7000));
        thread1.start();
        Thread thread2 = new Thread(new ThreadedRedisRead(7002));
        thread2.start();
        Thread thread3 = new Thread(new ThreadedRedisRead(7004));
        thread3.start();
        thread1.join();
        thread2.join();
        thread3.join();
        System.out.println("Hello world!");


    }
}

Output

thread is running...
thread is running...
thread is running...
avg = 28
max = 172
min = 16
avg = 28
max = 139
min = 17
avg = 28
max = 138
min = 17
Hello world!

Python version - 3.9.6 redis-py version - 4.5.5

import time
from threading import Thread
import redis


def threaded_function(arg):
    def read_data(connection_obj, key):
        start = time.time_ns()
        connection_obj.hgetall(key)
        end = time.time_ns() - start
        return end / 1000000

    print("thread started "+str(arg))
    redis_pool = redis.ConnectionPool(host='127.0.0.1', port=int(arg), db=0)

    res = []
    for i in range(100):
        connection_object = redis.Redis(connection_pool=redis_pool)
        res.append(read_data(connection_object, "seller-1"))

    print("avg", sum(res) / len(res))
    print("max", max(res))
    print("min", min(res))


if __name__ == "__main__":
    thread1 = Thread(target = threaded_function, args = (7000, ))
    thread1.start()
    thread2 = Thread(target = threaded_function, args = (7002, ))
    thread2.start()
    thread3 = Thread(target = threaded_function, args = (7004, ))
    thread3.start()
    thread1.join()
    thread2.join()
    thread3.join()
    print("thread finished...exiting")

Output -

thread started 7000
thread started 7002
thread started 7004
avg 87.73813000000001
max 104.335
min 75.594
avg 87.86647999999992
max 110.966
min 71.124
avg 91.26289000000004
max 118.033
min 30.482
thread finished...exiting

AkashBera avatar May 23 '23 14:05 AkashBera