gpt4 book ai didi

c# - WebClient 超时花费的时间比预期的要长(使用 : Rx, Try Catch,任务)

转载 作者:行者123 更新时间:2023-11-30 20:23:41 24 4
gpt4 key购买 nike

问题:我继承了WebClientExtendedWebClient我在哪里覆盖 WebRequest GetWebRequest 中的超时属性方法。如果我把它设置为 100 毫秒,甚至 20 毫秒,它总是至少需要 30 多秒。有时它似乎根本无法通过。

此外,当提供图像的服务(见下面的代码)再次上线时,用 Rx/System.Reactive 编写的代码不再将图像推送到 pictureBox 中了吗?

我该如何解决这个问题,我做错了什么? (见下面的代码)


测试用例:我为此设置了一个 WinForms 测试项目,它正在执行以下操作。

  1. GetNextImageAsync

    public async Task<Image> GetNextImageAsync()
    {
    Image image = default(Image);

    try {
    using (var webClient = new ExtendedWebClient()) {
    var data = await webClient.DownloadDataTaskAsync(new Uri("http://SOMEIPADDRESS/x/y/GetJpegImage.cgi"));
    image = ByteArrayToImage(data);

    return image;
    }
    } catch {
    return image;
    }
    }
  2. 扩展网络客户端

    private class ExtendedWebClient : WebClient
    {
    protected override WebRequest GetWebRequest(Uri address)
    {
    var webRequest = base.GetWebRequest(address);
    webRequest.Timeout = 100;
    return webRequest;
    }
    }

3.1 展示代码(使用Rx)

注意:它实际上从未到达 pictures.Subscribe() 中的“else”语句 body 。

    var pictures = Observable
.FromAsync<Image>(GetNextImageAsync)
.Throttle(TimeSpan.FromSeconds(.5))
.Repeat()
;

pictures.Subscribe(img => {
if (img != null) {
pictureBox1.Image = img;
} else {
if (pictureBox1.Created && this.Created) {
using (var g = pictureBox1.CreateGraphics()) {
g.DrawString("[-]", new Font("Verdana", 8), Brushes.Red, new PointF(8, 8));
}
}
}
});

3.2 演示代码(使用Task.Run)

注意 1:这里调用了“else”主体,尽管 WebClient 超时的时间仍然比预期的要长....

注意 2:我不想使用这种方法,因为这样我无法“节流”图像流,我无法按正确的顺序获取它们,并且用我的图像流做其他事情......但这只是它工作的示例代码......

    Task.Run(() => {
while (true) {
GetNextImageAsync().ContinueWith(img => {
if(img.Result != null) {
pictureBox1.Image = img.Result;
} else {
if (pictureBox1.Created && this.Created) {
using (var g = pictureBox1.CreateGraphics()) {
g.DrawString("[-]", new Font("Verdana", 8), Brushes.Red, new PointF(8, 8));
}
}
}
});
}
});
  1. 作为引用,传输 byte[] 的代码到 Image对象。

    public Image ByteArrayToImage(byte[] byteArrayIn)
    {
    using(var memoryStream = new MemoryStream(byteArrayIn)){
    Image returnImage = Image.FromStream(memoryStream);
    return returnImage;
    }
    }

最佳答案

另一个问题...

我将在下面解决取消问题,但对以下代码的行为也存在误解,无论取消问题如何,这都会导致问题:

var pictures = Observable
.FromAsync<Image>(GetNextImageAsync)
.Throttle(TimeSpan.FromSeconds(.5))
.Repeat()

您可能认为此处的Throttle 会限制GetNextImageAsync 的调用率。可悲的是,情况并非如此。考虑以下代码:

var xs = Observable.Return(1)
.Throttle(TimeSpan.FromSeconds(5));

您认为在订阅者上调用 OnNext(1) 需要多长时间?如果你认为 5 秒,你就错了。由于 Observable.Return 在其 OnNext(1) 之后立即发送了一个 OnCompleted,因此 Throttle 推断没有更多可能会限制 OnNext(1) 并立即发出的事件。

与我们创建非终止流的这段代码对比:

var xs = Observable.Never<int>().StartWith(1)
.Throttle(TimeSpan.FromSeconds(5));

现在 OnNext(1) 在 5 秒后到达。

所有这一切的结果是,您无限期的 Repeat 会破坏您的代码,请求图像与它们到达时一样快 - 这究竟是如何导致您所看到的效果需要进一步分析。

根据您的要求,有几种结构可以限制查询速率。一种是简单地在结果中附加一个空延迟:

var xs = Observable.FromAsync(GetValueAsync)                       
.Concat(Observable.Never<int>()
.Timeout(TimeSpan.FromSeconds(5),
Observable.Empty<int>()))
.Repeat();

在这里,您可以将 int 替换为 GetValueAsync 返回的类型。

取消

正如@StephenCleary 所观察到的,设置WebRequestTimeout 属性只会对同步请求有效。在查看了使用 WebClient 干净地实现取消的必要更改之后,我不得不同意它与 WebClient 一样,如果可能的话,您最好转换为 HttpClient

遗憾的是,即便如此,GetByteArrayAsync 等“简单”的数据提取方法也没有(出于某些奇怪的原因)接受 CancellationToken 的重载。

如果您确实使用 HttpClient,那么超时处理的一个选项是通过 Rx,如下所示:

void Main()
{
Observable.FromAsync(GetNextImageAsync)
.Timeout(TimeSpan.FromSeconds(1), Observable.Empty<byte[]>())
.Subscribe(Console.WriteLine);
}

public async Task<byte[]> GetNextImageAsync(CancellationToken ct)
{
using(var wc = new HttpClient())
{
var response = await wc.GetAsync(new Uri("http://www.google.com"),
HttpCompletionOption.ResponseContentRead, ct);
return await response.Content.ReadAsByteArrayAsync();
}
}

在这里,我使用了 Timeout 运算符来在超时事件中发出一个空流 - 其他选项可用,具体取决于您的需要。

Timeout 确实超时时,它将取消它对 FromAsync 的订阅,这反过来又会取消它间接传递给 HttpClient.GetAsync 的取消标记通过 GetNextImageAsync

您也可以使用类似的结构在 WebRequest 上调用 Abort,但正如我所说,如果不直接支持取消,这就更麻烦了代币。

关于c# - WebClient 超时花费的时间比预期的要长(使用 : Rx, Try Catch,任务),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28392420/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com