Reputation: 728
I have an app (http web load test app) that need new Thread()
, and the HttpClient
only have async method, so how do I run the action synchronous
ps: I tried use full Task
but the thread number it use is low (30 thread only),
so I want to try the Thread
to see if it can be much faster.
Will the .GetAwaiter().GetResult()
cost 2 thread (100 thread became 200 thread) ?
previous I use
for(var i = 0; i< 200;i++)
{
Task.Run(async ()=>
{
while(thereStillHaveRequestToMake)
{
await httpclient.SendAsync() // some thing like this
}
});
}
// the prolem is there are only 30-40 Thread in use (From TaskManager)
So I want to switch to use Thread directly
for(var i = 0; i< 200;i++)
{
new Thread(()=>
{
while(thereStillHaveRequestToMake)
{
httpclient.SendAsync().GetAwaiter.GetResult()
}
});
}
Upvotes: 0
Views: 2222
Reputation: 54618
I have an app (http web load test app) that need new Thread()
Why?
HttpClient only have async method, so how do I run the action synchronously
Why.
Or How to call asynchronous method from synchronous method in C#?.
I tried use full Task but the thread number it use is low (30 thread only),
A task is not a thread. We can easily test this by running methods on the thread pool. First we set the ThreadPool to only allow a single thread.
class Program
{
private const int MaxThreads = 1;
static void Main(string[] args)
{
ThreadPool.SetMinThreads(MaxThreads, 1);
Console.WriteLine(ThreadPool.SetMaxThreads(MaxThreads, 1));
Task.Run(() => SomeMethod(new StateInfo { Order = 0, WaitFor = 3000 }));
Task.Run(() => SomeMethod(new StateInfo { Order = 1, WaitFor = 3000 }));
Task.Run(() => SomeMethod(new StateInfo { Order = 2, WaitFor = 3000 }));
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(5000);
Console.WriteLine("Main thread exits.");
}
static void SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
Thread.Sleep(si.WaitFor);
}
public class StateInfo
{
public int Order { get; set; }
public int WaitFor { get; set; }
}
}
Output
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 2
Main thread exits.
Since we have 1 thread and we've told the first two methods to wait a total of 6 seconds, but the main thread exits after 5 seconds, we never get a message from the 3rd method. We can easily test this by changing MaxThreads = 2
which yields something like the following (we get 3 results, but not necessarily in order):
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 2
Hello from the thread pool. 3
Main thread exits.
Now that we've guaranteed we're using a single thread, lets see how many requests we can do simultaneously synchronously.
static void SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
httpClient.GetStringAsync($"https://www.google.com");
Console.WriteLine($"Hello from the thread pool. {si.Order} finished");
}
Since we aren't async/await the request, it runs synchronously so the output is predictably:
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 1 finished
Hello from the thread pool. 2
Hello from the thread pool. 2 finished
Hello from the thread pool. 3
Hello from the thread pool. 3 finished
Main thread exits.
That doesn't really load test anything because synchronous calls wait until the previous one finishes. In order to load test we want many concurrent calls. This is easily done with a single thread using async await.
Update the method:
static async Task SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
await httpClient.GetStringAsync($"https://www.google.com");
Console.WriteLine($"Hello from the thread pool. {si.Order} finished");
}
Use linq to make a list of requests, and wait for all of them to finish.
static void Main(string[] args)
{
ThreadPool.SetMinThreads(MaxThreads, 1);
Console.WriteLine(ThreadPool.SetMaxThreads(MaxThreads, 1));
Console.WriteLine("Start Requests");
var requests = Enumerable.Range(0, 200)
.Select(async (x) => await Task.Run(() => SomeMethod2(new StateInfo { Order = x, WaitFor = 0 })))
.ToArray();
Console.WriteLine("Wait for them.");
Task.WaitAll(requests.ToArray());
Console.WriteLine("Main thread exits.");
Console.ReadKey();
}
Yields (I didn't want to put 400 lines of code here)
True
Start Requests
Wait for them.
Hello from the thread pool. 0
Hello from the thread pool. 1
Hello from the thread pool. 2
.... repeating to
Hello from the thread pool. 199
Hello from the thread pool. 178 finished
Hello from the thread pool. 5 finished
Hello from the thread pool. 3 finished
Hello from the thread pool. 15 finished
Hello from the thread pool. 26 finished
Hello from the thread pool. 4 finished
.... repeating until all 200 requests are finished
Main thread exits.
200 Http Requests on a single thread. Why do you need more threads?
Upvotes: 1