多个web请求,在等待最后一个请求的响应时启动另一个请求。C#

多个web请求,在等待最后一个请求的响应时启动另一个请求。C#,c#,multithreading,async-await,httpwebrequest,C#,Multithreading,Async Await,Httpwebrequest,我正在尝试从需要很长时间才能加载完整响应(非常长的日志文件)的网站执行多个web请求。我想实现一种方法,在等待其他请求响应的同时继续创建web请求,并加快进程 尝试实现一个异步等待方法,但我认为它不会创建同步调用,而是同步运行。我对如何实现async Wait感到非常困惑,我研究了其他类似的问题,但仍然不太清楚,如何修复此代码以运行async? 这是我的代码: public static async Task<String> MakeRequestAsync(Stri

我正在尝试从需要很长时间才能加载完整响应(非常长的日志文件)的网站执行多个web请求。我想实现一种方法,在等待其他请求响应的同时继续创建web请求,并加快进程

尝试实现一个异步等待方法,但我认为它不会创建同步调用,而是同步运行。我对如何实现async Wait感到非常困惑,我研究了其他类似的问题,但仍然不太清楚,如何修复此代码以运行async?
这是我的代码:

        public static async Task<String> MakeRequestAsync(String url)
    {
        String responseText = null;

            try
            {
                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Proxy = null;
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                string sr = new StreamReader(responseStream).ReadToEnd();
                response.Close();
                responseStream.Close();
                responseText = sr;
            }

            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }
        return responseText;
    }
公共静态异步任务MakeRequestAsync(字符串url)
{
字符串responseText=null;
尝试
{
HttpWebRequest-request=WebRequest.Create(url)为HttpWebRequest;
Proxy=null;
WebResponse=request.GetResponse();
Stream responseStream=response.GetResponseStream();
string sr=new StreamReader(responseStream).ReadToEnd();
response.Close();
responseStream.Close();
responseText=sr;
}
捕获(例外e)
{
Console.WriteLine(“错误:+e.Message”);
}
返回响应文本;
}

private void按钮\u测试\u单击(对象发送方,事件参数e)
{
for(int n=0;n<5;n++)//多个请求
{
字符串a=AsyncTest().Result;
}
}
专用异步任务AsyncTest()
{
字符串b=等待MakeRequestAsync(url);
返回b;
}

另外,关于如何加快此过程的任何建议都将非常有用。

您的IO调用都不是异步的
WebRequest
也没有
async/await
模式,您可以使用
BeginGetResponse
AsyncCallback
获得
async
行为,但还有更好的方法。使用
HttpClient
相反,它是进行http调用的推荐方法


您应该使用微软的反应式框架(aka Rx)-NuGet
System.Reactive
并使用System.Reactive.Linq添加
-然后您可以执行以下操作:

var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select new { n, r };

IDisposable subscription =
    query
        .ToArray()
        .Select(xs => xs.OrderBy(x => x.n).Select(x => x.r).ToArray())
        .Subscribe(rs =>
        {
            /* Do something with the results */
        });
它都是多线程和非阻塞的

如果您不关心返回结果的顺序,那么只需执行以下操作:

var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select r;

IDisposable subscription =
    query
        .Subscribe(r =>
        {
            /* Do something with each result */
        });
如果需要取消查询,调用subscription.Dispose()
将停止查询


您可以这样编写
MakeRequestAsync
方法:

public static async Task<String> MakeRequestAsync(String url)
{
    return await
        Observable.Using(
            () => new WebClient(),
            wc => Observable.Start(() => wc.DownloadString(url)));
}
公共静态异步任务MakeRequestAsync(字符串url)
{
返回等待
可观察的。使用(
()=>新的WebClient(),
wc=>Observable.Start(()=>wc.DownloadString(url));
}

“WebRequest也没有异步/等待模式”-哇,真的吗+1此操作正常,它等待第一次调用的响应,同时发出其他请求,但一段时间后,第一次调用从未完成(慢速请求),并引发System.Threading.Tasks.TaskCanceledException:'任务已取消。'异常,这是请求的某种超时吗?@BLM听起来像是一个新问题?@BLM是的,这是一个超时问题。您需要在http ClientFollowing question上设置
Timeout
属性->此解决方案在下载字符串时是否会使用阻止的5个线程?它就像一个符咒一样工作,尽管如果我尝试从此方法返回字符串r,我会收到一个错误:“转换为无效返回委托的匿名函数无法返回值”。通过此方法可以执行何种类型的返回以访问字符串?@BLM
WebClient.DownloadString
是一种阻塞操作。这意味着您需要启动后台线程,这些线程只是挂起,等待结果的出现。这意味着您正在无缘无故地抢夺线程池中的工作线程。@JohanP-
WebClient.DownloadString
如果在当前线程上调用,则是一个阻塞操作,但Rx会推送到后台线程。您可以完全控制所使用的调度。@BLM-我已经为您的
MakeRequestAsync
方法添加了代码。
var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select new { n, r };

IDisposable subscription =
    query
        .ToArray()
        .Select(xs => xs.OrderBy(x => x.n).Select(x => x.r).ToArray())
        .Subscribe(rs =>
        {
            /* Do something with the results */
        });
var query =
    from n in Observable.Range(0, 5)
    from r in Observable.Using(
        () => new WebClient(),
        wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
    select r;

IDisposable subscription =
    query
        .Subscribe(r =>
        {
            /* Do something with each result */
        });
public static async Task<String> MakeRequestAsync(String url)
{
    return await
        Observable.Using(
            () => new WebClient(),
            wc => Observable.Start(() => wc.DownloadString(url)));
}