StackExchange / StackExchange.Redis

General purpose redis client
https://stackexchange.github.io/StackExchange.Redis/
Other
5.86k stars 1.5k forks source link

performance advise #2584

Open pianoman4873 opened 9 months ago

pianoman4873 commented 9 months ago

Hello, Assuming funcAsync are mainly readAsync / writeAsync calls to Redis using the StackExchange.Redis client - which implementation of BatchExecuteAsync would be preferrable for better throughput / efficiency etc. ( especially when considering nature of the multiplexing going on behind the scenes ) ?

Thanks

public static async Task BatchedExecuteAsync<TItem>(this List<TItem> items, Func<TItem, Task> funcAsync, int amountOfParallelism)
{

    var tasks = new List<Task>(amountOfParallelism);
    int index = 0;
    for (var i = 0; i < amountOfParallelism; i++)
    {
        tasks.Add(Task.Run(async () =>
        {
            while (true)
            {
                TItem item;
                lock (tasks)
                {
                    if (index >= items.Count)
                    {
                        break;
                    }

                    item = items[index];
                    index++;
                }

                await funcAsync(item);
            }
        }));
    }

    await Task.WhenAll(tasks);
}

 public static async Task BatchedExecuteAsync<TItem>(this IEnumerable<TItem> items, Func<TItem,Task> funcAsync, int amountOfParallelism)
        {

            var tasks = new List<Task>(amountOfParallelism);
            foreach (var item in items)
            {
                tasks.Add(funcAsync ( item));
                if (tasks.Count == amountOfParallelism)
                {
                    await Task.WhenAll(tasks);
                    tasks.Clear();
                }
            }
            if (tasks.Count > 0)
            {
                await Task.WhenAll(tasks);

            }
     }
NickCraver commented 8 months ago

What are you trying to accomplish in your batching here? Why are you batching? (We need more context to answer this - looking immediately I couldn't recommend either implementation as there's extra async and allocation overhead happening when you can likely avoid it)

pianoman4873 commented 7 months ago

Hi, I'm trying to process many requests ( for example read requests for various keys ) - I assume sending them all and await them all together would incur too much load , so batching is used.

mgravell commented 7 months ago

There's no significant difference between those two scenarios (with/without batch), except that when using the batch API you're delaying the first send by a few picoseconds (until you call execute). However: if your use case is reading multiple keys, then: a multi-key fetch already exists - maybe just use that? (if the key volume is huge you may want to split this into chunks so you don't block competing clients)