【问题标题】:async await web api file io异步等待 web api 文件 io
【发布时间】:2013-02-27 07:59:51
【问题描述】:

我在 Web api 控制器中使用以下异步代码来处理 XML 文件。一切都按预期工作,但是这是 async/await 方法的正确使用。我基本上是从 XML 文件中提取所有图像,然后将它们保存到磁盘。我想尝试最小化文件 io 的影响。

public async Task<HttpResponseMessage> PostFile()
{
    await Task.WhenAll(this.ProcessProofOfPressenceImages(address, images, surveyReference), this.ProcessSketchImages(propertyPlans, images, surveyReference), this.ProcessExteriorImages(exteriorSketch, images, surveyReference));
    //db code
}

private async Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
    }
}

private async Task ProcessSketchImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "sketchPlanImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchFrontImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchRearImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchLeftSideImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchRightSideImage"));
    }
}

private async Task ProcessExteriorImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    List<Task> tasks = new List<Task>();

    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "image1"), this.ProcessImagesHelper(container, images, surveyReference, "image2"), this.ProcessImagesHelper(container, images, surveyReference, "image3"), this.ProcessImagesHelper(container, images, surveyReference, "image4"), this.ProcessImagesHelper(container, images, surveyReference, "image5"), this.ProcessImagesHelper(container, images, surveyReference, "image6"));
    }
}

private async Task ProcessImagesHelper(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference, string image)
{
    if(container.ContainsKey(image) && !String.IsNullOrEmpty(container[image].ToString()))
    {
        using(MemoryStream memoryStream = new MemoryStream((byte[])container[image]))
        {
            string url = String.Format(@"{0}{1}{2}_{3}.jpg", EcoConfiguration.Instance.RootUrl, EcoConfiguration.Instance.SurveyImageRootUrl, surveyReference, image.SplitOnCapital("_"));

            using(FileStream fileStream = new FileStream(url, FileMode.Create, FileAccess.Write))
            {
                Dictionary<string, string> imageDetails = new Dictionary<string, string>();
                imageDetails.Add("TypeId", ((int)SurveyImageType.Exterior).ToString());
                imageDetails.Add("ImageUrl", url);
                if(container.ContainsKey(image + "Description"))
                {
                    imageDetails.Add("Description", container[image + "Description"].ToSafeString());
                }
                images.Add(imageDetails);
                await memoryStream.CopyToAsync(fileStream);
            }
        }
    }
}

非常欢迎任何 cmets/建议。

【问题讨论】:

    标签: c# asp.net-web-api asp.net-4.5


    【解决方案1】:

    文件流的棘手之处在于您需要将isAsync: trueFileOptions.Asynchronous 传递给构造函数/工厂方法才能获得真正的异步流。如果你不这样做,那么底层文件流实际上是阻塞的,异步方法只是使用线程池来伪造异步操作。

    在您的代码中让我印象深刻的另一件事是您对async 进行了一些不必要的使用。 async 应该仅在您需要时使用。例如,这种方法:

    private async Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
    {
      if(images != null)
      {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
      }
    }
    

    可以写成:

    private Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
    {
      if(images != null)
      {
        return Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
      }
    
      return Task.FromResult<object>(null);
    }
    

    这为您节省了不必要的状态机。同样的建议也适用于ProcessSketchImagesProcessExteriorImages

    关于ProcessImagesHelper,它看起来不错,虽然我不确定你为什么需要MemoryStream。 (异步)将字节数组写入磁盘同样容易。

    如果您对async 性能提示感兴趣,请联系Stephen Toub has an excellent video

    【讨论】:

    • Stephen,感谢您的回复和建议 - 非常感谢 - 所有异步方法都感觉不对!我已按照建议更改了代码,并删除了对 MemoryStream 的需求,并将 isAsync 参数设置为 true。我使用另一篇文章 (stackoverflow.com/questions/1862982/…) 来确定 FileStream 的最佳缓冲区大小。
    猜你喜欢
    • 2021-06-28
    • 2015-02-03
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    相关资源
    最近更新 更多