因此,在涉足 Java 和 HttpClient 之后,我决定转向 C#,尝试在提高速度的同时降低内存使用量。我已经阅读了这里的成员提供的大量有关异步与多线程的文章。看来多线程将是更好的方向。
我的程序将访问服务器并一遍又一遍地发送相同的请求,直到检索到 200 代码。原因是因为在高峰时段交通量非常大。它使得服务器非常难以访问并抛出 5xx 错误。代码非常简单,我不想添加循环来帮助观众简化。
我觉得我正朝着正确的方向前进,但我想向社区伸出援手,改掉任何坏习惯。再次感谢您的阅读。
版主注意:我要求检查我的代码是否存在差异,我很清楚多线程 HttpClient 是可以的。
using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Threading;
namespace MF
{
class MainClass
{
public static HttpClient client = new HttpClient();
static string url = "http://www.website.com";
public static void getSession() {
StringContent queryString = new StringContent("{json:here}");
// Send a request asynchronously continue when complete
var result = client.PostAsync(new Uri(url), queryString).Result;
// Check for success or throw exception
string resultContent = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(resultContent);
}
public static void Run()
{
getSession ();
// Not yet implemented yet..
//doMore ();
}
public static void Main (string[] args)
{
Console.WriteLine ("Welcome!");
// Create the threads
ThreadStart threadref1 = new ThreadStart(Run);
ThreadStart threadref2 = new ThreadStart(Run);
Console.WriteLine("In the main: Creating the threads...");
Thread Thread1 = new Thread(threadref1);
Thread Thread2 = new Thread(threadref1);
// Start the thread
Thread1.Start();
Thread2.Start();
}
}
}
另外,我不确定这是否重要,但我正在我的 MacBook Pro 上运行它,并计划在我的 BeagleBoard 上运行它。
如果我是你,我会这样做。我会尽可能地利用异步,因为它比使用线程更有效(您很可能不必一直进行上下文切换,这是昂贵的)。
class MainClass
{
public static HttpClient client = new HttpClient();
static string url = "http://www.website.com";
public static async Task getSessionAsync()
{
StringContent queryString = new StringContent("{json:here}");
// Send a request asynchronously continue when complete
using (HttpResponseMessage result = await client.PostAsync(url, queryString))
{
// Check for success or throw exception
string resultContent = await result.Content.ReadAsStringAsync();
Console.WriteLine(resultContent);
}
}
public static async Task RunAsync()
{
await getSessionAsync();
// Not yet implemented yet..
//doMore ();
}
public static void Main(string[] args)
{
Console.WriteLine("Welcome!");
const int parallelRequests = 5;
// Send the request X times in parallel
Task.WhenAll(Enumerable.Range(1, parallelRequests).Select(i => RunAsync())).GetAwaiter().GetResult();
// It would be better to do Task.WhenAny() in a while loop until one of the task succeeds
// We could add cancellation of other tasks once we get a successful response
}
}
请注意,我确实同意@Damien_The_Unknowner:如果服务器在重负载下出现问题,您不应该添加不必要的负载(执行X次相同的请求)并导致服务器出现问题。理想情况下,您会修复服务器代码,但我可以理解它不是您的。
弄乱标头不是线程安全的。
例如,用新的 OAuth 访问令牌替换 OAuth 访问令牌不是线程安全的。现在使用 Xamarin 移动应用程序来面对这个问题。我有一份崩溃报告,其中一个线程正在修改标头,而另一个线程正在尝试请求。
以下方法是线程安全的:
CancelPendingRequests
DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync
更多详情:
阅读 HttpClient 的文档:
此类型的任何公共静态(在 Visual Basic 中为共享)成员都是线程安全的。不保证任何实例成员都是线程安全的。
不要冒险。每个线程都有一个单独的 HTTP 客户端。
您似乎正在阻塞等待回复的线程,并且您正在从一个不执行任何额外操作的线程中执行此操作。那为什么还要费心async/await呢?您可以使用简单的阻塞调用。此外 - 您的程序现在在启动线程后立即完成。您可能需要等待线程完成后再从 main 返回。您可以通过程序末尾的这段代码来做到这一点:
Thread1.Join();
Thread2.Join();
根据评论更新:
以下注释:
我正在调试一些不断修改此属性的代码,而没有考虑未完成的请求。这导致了奇怪的异常,堆栈跟踪深入内部
DefaultRequestHeaders
当有未完成的请求时,不应修改。
HttpClient
:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Net.Http.HttpConnection.WriteAsciiStringAsync(String s, Boolean async)
at System.Net.Http.HttpConnection.WriteHeadersAsync(HttpHeaders headers, String cookiesFromContainer, Boolean async)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
正确的修复显然不是在每个请求上修改 httpClient.DefaultRequestHeaders.Authorization
,而是使用所需的标头实例化
new HttpRequestMessage
。