带有异步任务功能的线程C# /.Net /等待不编译



我有一个项目,我需要多个项目来列出项目列表。对于每个项目,我都会致电API,以获取此信息。循环起作用,尽管需要4到5分钟才能完成(很多)。

用来像这样的代码:

foreach (var project in projects)
{
    string url = urlOneProject + project.name + secondPartUrl + "?authtoken=" + authToken;
    HttpWebRequest request;
    request = (HttpWebRequest)WebRequest.Create(url);
    request.Accept = "application/json";
    request.ContentType = "application/json";
    var executions = new Execs();
    var response = (HttpWebResponse)(await request.GetResponseAsync());
    using (response)
    {
        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            JavaScriptSerializer js = new JavaScriptSerializer();
            var objText = reader.ReadToEnd();
            executions = (Execs)js.Deserialize(objText, typeof(Execs));
        }
    }

    execs.AddRange(executions.executions);
} 

为了提高性能,我认为使用线程可能是个好主意。所以,我想出了这样的事情:

ManualResetEvent resetEvent = new ManualResetEvent(false);
int toProcess = projects.Count;
foreach (var project in projects)
{
    new Thread(() =>
    {
        string url = urlOneProject + project.name + secondPartUrl + "?authtoken=" + authToken;
        HttpWebRequest request;
        request = (HttpWebRequest)WebRequest.Create(url);
        request.Accept = "application/json";
        request.ContentType = "application/json";
        var executions = new Execs();
        var response = (HttpWebResponse)(await request.GetResponseAsync());
        using (response)
        {
            using (var reader = new StreamReader(response.GetResponseStream()))
            {
                JavaScriptSerializer js = new JavaScriptSerializer();
                var objText = reader.ReadToEnd();
                executions = (Execs)js.Deserialize(objText, typeof(Execs));
            }
        }
        lock (execs)
        {
            execs.AddRange(executions.executions);
        }
        if (Interlocked.Decrement(ref toProcess) == 0)
            resetEvent.Set();
    }).Start();
}

此代码的问题是行:

var response = (HttpWebResponse)(await request.GetResponseAsync());

从我添加Thread的那一刻起不再编译。我得到的错误是

"等待'运算符只能在异步lambda表达式中使用"

当我不使用线程时,这不是问题。GetResponseAsyncasync功能,await的使用是强制性的。我尝试删除它(我同意这不是逻辑上的,但我没有选项),但是编译器告诉我,我需要awaitasync功能。我不太了解Thread的实现发生了什么变化。

我不是正确地使用线程吗?我该怎么做才能纠正或实施我想正确执行的操作?

您正在混合编码的多个范式,viz async / await和Oldschool线程启动和同步,这可能会导致麻烦。

根据上述评论

  • 您的代码未编译的原因是,您正在尝试在传递给线程的同步代码中使用await。您也可以将Lambdas作为async
  • TaskThread更安全,TPL提供了丰富而表达的工具来协助异步和并行性。
  • 如果您孤立地处理每个并行任务,而无需共享任何数据(例如您要锁定的集合),而是从每个任务中返回所得数据,则可以使用LINQ将结果整理到线程安全中方式。

var myTasks = projects.Select(async project =>
{
    var url = $"urlOneProject{project.name}{secondPartUrl}?authtoken={authToken}";
    var request = (HttpWebRequest) WebRequest.Create(url);
    request.Accept = "application/json";
    request.ContentType = "application/json";
    using (var response = (HttpWebResponse) (await request.GetResponseAsync()))
    using (var reader = new StreamReader(response.GetResponseStream()))
    {
        var objText = await reader.ReadToEndAsync();
        return JsonConvert.DeserializeObject<Execs>(objText);
    }
});
var execs = (await Task.WhenAll(myTasks))
    .SelectMany(result => result.executions);

其他注释

  • 不要使用JavaScriptSerializer-即使是MSDN Docco都说使用Newtonsoft JSON
  • 我包括的reader.ReadToEndAsync有一个异步版本。
  • 您可以放下锁和ManualResetEvent-由于每个任务返回结果,我们将其保留到Task.WhenAll来整理数据。
  • 您可以用SelectMany
  • 将多个executions的孩子弄平
  • 相邻的using条款是可堆叠的 - 它可以节省一些眼睛的凹痕。

相关内容

  • 没有找到相关文章

最新更新