【发布时间】:2018-03-29 13:10:15
【问题描述】:
我正在编写一个需要从多个 WebSocket 连续读取数据的 .NET Core 控制台应用程序。我目前的方法是为每个 WebSocket 创建一个新任务(通过 Task.Run),该任务运行一个无限的 while 循环并阻塞,直到它从套接字读取数据。然而,由于数据推送的频率相当低,线程大部分时间只是阻塞,这看起来效率很低。
根据我的理解,异步/等待模式应该是阻塞 I/O 操作的理想选择。但是,我不确定如何将它应用于我的情况,或者即使 async/await 可以以任何方式改善这一点 - 特别是因为它是一个控制台应用程序。
我已经整理了一个概念证明(为了简单起见,使用 HTTP GET 而不是从 WebSocket 读取)。我能够做到这一点的唯一方法是没有真正等待。代码:
static void Main(string[] args)
{
Console.WriteLine($"ThreadId={ThreadId}: Main");
Task task = Task.Run(() => Process("https://duckduckgo.com", "https://stackoverflow.com/"));
// Do main work.
task.Wait();
}
private static void Process(params string[] urls)
{
Dictionary<string, Task<string>> tasks = urls.ToDictionary(x => x, x => (Task<string>)null);
HttpClient client = new HttpClient();
while (true)
{
foreach (string url in urls)
{
Task<string> task = tasks[url];
if (task == null || task.IsCompleted)
{
if (task != null)
{
string result = task.Result;
Console.WriteLine($"ThreadId={ThreadId}: Length={result.Length}");
}
tasks[url] = ReadString(client, url);
}
}
Thread.Yield();
}
}
private static async Task<string> ReadString(HttpClient client, string url)
{
var response = await client.GetAsync(url);
Console.WriteLine($"ThreadId={ThreadId}: Url={url}");
return await response.Content.ReadAsStringAsync();
}
private static int ThreadId => Thread.CurrentThread.ManagedThreadId;
这似乎在 ThreadPool 上的各种工作线程上工作和执行。但是,这绝对不是任何典型的 async/await 代码,这让我认为必须有更好的方法。
有没有更合适/更优雅的方式来做到这一点?
【问题讨论】:
-
我认为对于您的用例,可观察流非常适合。尝试:reactivex.io
-
所以基本上......你有一个 URL 列表,你想向每个 URL 发起一个请求,然后当每个请求完成时你想处理它,然后发送另一个请求?
-
@Rawling - 非常相似,只是使用 WebSockets。我正在等待数据被推送,然后读取它,隐藏它,存储它,然后再次读取。推送频率范围为 1 分钟 - 1 天。
标签: c# async-await .net-core console-application