我有一个需要new Thread()
的应用程序(http Web负载测试应用程序),而HttpClient
仅具有异步方法,所以我该如何同步运行操作
ps:我尝试使用完整的Task
,但是它使用的线程数很低(仅30个线程),
所以我想尝试Thread
来看看它是否可以更快。
.GetAwaiter().GetResult()
会花费2个线程(100个线程变为200个线程)吗?
以前使用的是
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)
所以我想直接使用Thread
for(var i = 0; i< 200;i++)
{
new Thread(()=>
{
while(thereStillHaveRequestToMake)
{
httpclient.SendAsync().GetAwaiter.GetResult()
}
});
}
答案 0 :(得分:2)
我有一个需要新Thread()的应用程序(http Web负载测试应用程序)
为什么?
HttpClient仅具有异步方法,因此如何同步运行操作
为什么。
或How to call asynchronous method from synchronous method in C#?。
我尝试使用完整的Task,但是它使用的线程数很低(仅30个线程),
任务不是线程。通过在线程池上运行方法,我们可以轻松地对此进行测试。首先,我们将ThreadPool设置为仅允许一个线程。
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; }
}
}
输出
是
主线程完成一些工作,然后进入睡眠状态。
您好,来自线程池。 1
您好,来自线程池。 2
主线程退出。
由于我们有1个线程,并且已经告知前两个方法总共等待6秒,但是主线程在5秒后退出,因此我们永远不会从第3个方法收到消息。我们可以通过更改MaxThreads = 2
来轻松地测试它,其结果如下所示(我们得到3个结果,但不一定是顺序的):
是
主线程完成一些工作,然后进入睡眠状态。
您好,来自线程池。 1
您好,来自线程池。 2
您好,来自线程池。 3
主线程退出。
现在,我们已经保证我们使用的是单个线程,让我们看看同步可以同时执行多少个请求。
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");
}
由于我们不是 async / await 请求,因此它会同步运行 ,因此输出可以预测:
是
主线程完成一些工作,然后进入睡眠状态。
您好,来自线程池。 1
您好,来自线程池。 1个完成
您好,来自线程池。 2
您好,来自线程池。 2完成
您好,来自线程池。 3
您好,来自线程池。 3完成
主线程退出。
这实际上并不会进行任何负载测试,因为 synchronous 调用要等到前一个完成为止。为了进行负载测试,我们需要许多 concurrent 调用。这可以通过使用异步等待的单个线程轻松完成。
更新方法:
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");
}
使用linq列出请求,然后等待所有请求完成。
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();
}
收益(我不想在这里放置400行代码)
在单个线程上是
开始请求
等他们。
您好,来自线程池。 0
您好,来自线程池。 1
您好,来自线程池。 2
....重复
您好,来自线程池。 199
您好,来自线程池。 178完成
您好,来自线程池。 5完成
您好,来自线程池。 3完成
您好,来自线程池。 15完成
您好,来自线程池。 26完成
您好,来自线程池。 4完成
....重复直到所有200个请求都完成
主线程退出。
200个Http请求。为什么需要更多线程?