question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Request threading issues?

See original GitHub issue

Hi Colin, I’m doing some fairly basic tests at the moment to explore throughput. I’ve a system that I want to Request about 20 sources and aggregate the results.

If I just use publish (using the same approach as below), then I can comfortably publish 10,000 messages in <300ms on my PC. So I put together the following snippet with Request, and I was expecting something similar, but am seeing NATSTimeoutException instead.

                Msg msg = null;
                ConnectionFactory cf = new ConnectionFactory();
                var sw = new Stopwatch();
                sw.Start();
                using (var c = cf.CreateConnection())
                {
                    var tasks = Enumerable.Range(0, 10000).Select(x =>
                         Task.Factory.StartNew(() =>
                         {
                           msg = c.Request("AppointmentSearch", new AppointmentSearch().ToMsg(), 10 * 1000);
                         })
                    );
                    Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(10));
                }
                return sw.ElapsedMilliseconds;

Looking at gnatsd -V I can see a throughput of about 1 message per second. This doesn’t seem right to me? Is there anything I can look at?

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
ColinSullivan1commented, Apr 21, 2016

@chrismcv I agree, but think this has more to do with the task scheduler itself, than NATS code. I wrote a few tests using Tasks that failed quickly (running on VM), similar to your results. The tasks weren’t being scheduled in a performant manner, likely due to resources constraints. However, when I moved down to using threads I found the performance I was expecting. 300 threads requesting, with the responder randomly delaying up to 5 seconds, and the tests passed about the same time as the delay, indicating there was little to no contention in request calls. The responses were received were out of order, as expected, also indicating little contention. Each subscription does have its own channel, so they shouldn’t step on each other. This is an interesting problem… That being said, this needs to be addressed and I will continue looking.

1reaction
chrismcvcommented, Apr 20, 2016

I created the following method

 private Task<Msg> RequestAsync(IConnection c, string subject, byte[] data, int timeout)
        {
            var tcs = new TaskCompletionSource<Msg>();
            var ct = new CancellationTokenSource(timeout);
            ct.Token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: false);

            string inbox = c.NewInbox();

            var s = c.SubscribeAsync(inbox);
            s.AutoUnsubscribe(1);
            s.MessageHandler += (e, h) =>
            {
                tcs.TrySetResult(h.Message);
                try
                {
                    s.Unsubscribe();
                }
                catch { }
            };
            s.Start();
            c.Publish(subject, inbox, data);
            return tcs.Task;
        }

and using

Msg msg = null;
                var res = new ConcurrentBag<AppointmentSearchResponse>();
                ConnectionFactory cf = new ConnectionFactory();
                var sw = new Stopwatch();
                sw.Start();
                using (var c = cf.CreateConnection())
                {
                    var tasks = Enumerable.Range(0, 10000).Select(async x =>
                    {
                        msg = await RequestAsync(c, "AppointmentSearch", new AppointmentSearch().ToMsg(), 10 * 1000);
                        res.Add(msg.As<AppointmentSearchResponse>());
                    });
                    Task.WaitAll(tasks.ToArray(), 100000);
                }

I get much better throughput - e.g. 600ms for 10,000. I suspect the SubscribeSync in request is blocking other Tasks but SubscribeAsync isn’t.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Python Threading/Request issue
I have a multi-threading code in Python (firing several threads every second and closing them after), and it used to work fine. Recently,...
Read more >
What are threading issues
What are threading issues - We can discuss some of the issues to consider in designing multithreaded programs. These issued are as follows ......
Read more >
Managed Threading Best Practices
Multithreading requires careful programming. For most tasks, you can reduce complexity by queuing requests for execution by thread pool threads.
Read more >
How To Resolve Multi-Threading Problems
Whenever a thread wants to enter a critical region, it requests permission from the semaphore. If the semaphore counter is greater than zero, ......
Read more >
An Intro to Threading in Python
In this intermediate-level tutorial, you'll learn how to use threading in your Python programs. You'll see how to create threads, how to coordinate...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found