Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET核心Web API中运行并行异步任务并返回结果_C#_.net Core_Aws Lambda_Task Parallel Library_Asp.net Core Webapi - Fatal编程技术网

C# 在.NET核心Web API中运行并行异步任务并返回结果

C# 在.NET核心Web API中运行并行异步任务并返回结果,c#,.net-core,aws-lambda,task-parallel-library,asp.net-core-webapi,C#,.net Core,Aws Lambda,Task Parallel Library,Asp.net Core Webapi,您好,最近我在.net核心web api项目中工作,该项目正在从外部api下载文件。 在这个.net核心api中,最近发现了一些问题,而文件的数量超过了100个。API最多下载50个文件,并跳过其他文件。WebAPI部署在AWS Lambda上,超时为15mnts 实际上,由于下载过程很长,操作正在超时 public async Task<bool> DownloadAttachmentsAsync(List<DownloadAttachment> downloadAtt

您好,最近我在.net核心web api项目中工作,该项目正在从外部api下载文件。 在这个.net核心api中,最近发现了一些问题,而文件的数量超过了100个。API最多下载50个文件,并跳过其他文件。WebAPI部署在AWS Lambda上,超时为15mnts

实际上,由于下载过程很长,操作正在超时

public async Task<bool> DownloadAttachmentsAsync(List<DownloadAttachment> downloadAttachment)
        {
            try
            {
                bool DownloadFlag = false;

                foreach (DownloadAttachment downloadAttachment in downloadAttachments)
                {
                    DownloadFlag = await DownloadAttachment(downloadAttachment.id);

                    //update the download status in database
                    if(DownloadFlag)
                    {
                      bool UpdateFlag = await _DocumentService.UpdateDownloadStatus(downloadAttachment.id);

                      if (UpdateFlag)
                      {
                        await DeleteAttachment(downloadAttachment.id);
                      }
                   }
                }
                return true;
            }
            catch (Exception ext)
            {
                log.Error(ext, "Error in Saving attachment {attachemntId}",downloadAttachment.id);
                return false;
            }
        }
这种方法行吗?如何提高性能?如何获得每个并行任务的结果,并根据成功标志更新到DB和delete?或者此错误是由于AWS超时造成的


如果将处理单个文件的代码提取到单独的方法,请提供帮助:

private async Task DownloadSingleAttachment(DownloadAttachment attachment)
{
    try
    {
        var download = await DownloadAttachment(downloadAttachment.id);
        if(download)
        {
            var update = await _DocumentService.UpdateDownloadStatus(downloadAttachment.id);
            if (update)
            {
                await DeleteAttachment(downloadAttachment.id);
            }
        }
    }
    catch(....)
    {
    ....
    }
}

public async Task<bool> DownloadAttachmentsAsync(List<DownloadAttachment> downloadAttachment)
{
    try
    {
      foreach (var attachment in downloadAttachments)
      {
          await DownloadSingleAttachment(attachment);
      }
    }
    ....
}
这些块现在可以链接到管道中并使用。设置
PropagateCompletion=true
意味着一旦一个块完成处理,它将通知其所有连接的块也完成:

var linkOptions=new DataflowLinkOptions { PropagateCompletion = true};
downloader.LinkTo(updater, linkOptions);
updater.LinkTo(deleter,linkOptions);
只要我们需要,我们就可以将数据泵入头部模块。完成后,我们调用头块的
Complete()
方法。当每个块完成其数据处理时,它将把其完成情况传播到管道中的下一个块。我们需要等待最后一个(尾部)块完成,以确保已处理所有附件:

foreach (var attachment in downloadAttachments)
{
    await downloader.SendAsync(attachement.id);
}

downloader.Complete();
await deleter.Completion;
每个块都有一个输入和(必要时)一个输出缓冲区,这意味着消息的“生产者”和“消费者”不必同步,甚至不必相互了解。“生产商”需要知道的是在管道中的何处找到头块

节流和背压

限制的一种方法是通过
MaxDegreeOfParallelism
使用固定数量的任务

还可以对输入缓冲区进行限制,从而在块不能足够快地处理消息时阻止前面的步骤或生产者。只需为块设置以下参数即可:

var dlOptions= new ExecutionDataflowBlockOptions
{
    MaxDegreeOfParallelism = 10,
    BoundedCapacity=20,
};

var updaterOptions= new ExecutionDataflowBlockOptions
{
    BoundedCapacity=20,
};

...

var downloader=new TransformBlock<...>(...,dlOptions);

var updater=new TransformBlock<...>(...,updaterOptions);
var dlOptions=新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=10,
边界容量=20,
};
var updateoptions=新的ExecutionDataflowBlockOptions
{
边界容量=20,
};
...
var downloader=新TransformBlock(…,dlOptions);
var updater=newtransformblock(…,updateoptions);

如果将处理单个文件的代码提取到单独的方法,则无需进行其他更改:

private async Task DownloadSingleAttachment(DownloadAttachment attachment)
{
    try
    {
        var download = await DownloadAttachment(downloadAttachment.id);
        if(download)
        {
            var update = await _DocumentService.UpdateDownloadStatus(downloadAttachment.id);
            if (update)
            {
                await DeleteAttachment(downloadAttachment.id);
            }
        }
    }
    catch(....)
    {
    ....
    }
}

public async Task<bool> DownloadAttachmentsAsync(List<DownloadAttachment> downloadAttachment)
{
    try
    {
      foreach (var attachment in downloadAttachments)
      {
          await DownloadSingleAttachment(attachment);
      }
    }
    ....
}
这些块现在可以链接到管道中并使用。设置
PropagateCompletion=true
意味着一旦一个块完成处理,它将通知其所有连接的块也完成:

var linkOptions=new DataflowLinkOptions { PropagateCompletion = true};
downloader.LinkTo(updater, linkOptions);
updater.LinkTo(deleter,linkOptions);
只要我们需要,我们就可以将数据泵入头部模块。完成后,我们调用头块的
Complete()
方法。当每个块完成其数据处理时,它将把其完成情况传播到管道中的下一个块。我们需要等待最后一个(尾部)块完成,以确保已处理所有附件:

foreach (var attachment in downloadAttachments)
{
    await downloader.SendAsync(attachement.id);
}

downloader.Complete();
await deleter.Completion;
每个块都有一个输入和(必要时)一个输出缓冲区,这意味着消息的“生产者”和“消费者”不必同步,甚至不必相互了解。“生产商”需要知道的是在管道中的何处找到头块

节流和背压

限制的一种方法是通过
MaxDegreeOfParallelism
使用固定数量的任务

还可以对输入缓冲区进行限制,从而在块不能足够快地处理消息时阻止前面的步骤或生产者。只需为块设置以下参数即可:

var dlOptions= new ExecutionDataflowBlockOptions
{
    MaxDegreeOfParallelism = 10,
    BoundedCapacity=20,
};

var updaterOptions= new ExecutionDataflowBlockOptions
{
    BoundedCapacity=20,
};

...

var downloader=new TransformBlock<...>(...,dlOptions);

var updater=new TransformBlock<...>(...,updaterOptions);
var dlOptions=新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=10,
边界容量=20,
};
var updateoptions=新的ExecutionDataflowBlockOptions
{
边界容量=20,
};
...
var downloader=新TransformBlock(…,dlOptions);
var updater=newtransformblock(…,updateoptions);

要运行多个异步操作,无需进行其他更改。您可以执行以下操作:

    public async Task RunMultipleAsync<T>(IEnumerable<T> myList)
    {
        const int myNumberOfConcurrentOperations = 10;
        var mySemaphore = new SemaphoreSlim(myNumberOfConcurrentOperations);
        var tasks = new List<Task>();
        foreach(var myItem in myList)
        {
            await mySemaphore.WaitAsync();
            var task = RunOperation(myItem);
            tasks.Add(task);
            task.ContinueWith(t => mySemaphore.Release());           
        }

        await Task.WhenAll(tasks);
    }

    private async Task RunOperation<T>(T myItem)
    {
        // Do stuff
    }
public异步任务RunMultipleAsync(IEnumerable myList)
{
const int myNumberOfConcurrentOperations=10;
var mySemaphore=新信号量lim(myNumberOfConcurrentOperations);
var tasks=新列表();
foreach(myList中的var myItem)
{
等待mySemaphore.WaitAsync();
var任务=运行操作(myItem);
任务。添加(任务);
task.ContinueWith(t=>mySemaphore.Release());
}
等待任务。何时(任务);
}
专用异步任务运行操作(T myItem)
{
//做事
}
DownloadAttachmentsAsync
中的代码放在“Do stuff”注释处


这将使用信号量来限制并发操作的数量,因为由于争用,运行多个并发操作通常是个坏主意。您需要进行实验,为您的用例找到最佳并发操作数。还请注意,为了使示例简短,省略了错误处理。

要运行多个异步操作,可以执行以下操作:

    public async Task RunMultipleAsync<T>(IEnumerable<T> myList)
    {
        const int myNumberOfConcurrentOperations = 10;
        var mySemaphore = new SemaphoreSlim(myNumberOfConcurrentOperations);
        var tasks = new List<Task>();
        foreach(var myItem in myList)
        {
            await mySemaphore.WaitAsync();
            var task = RunOperation(myItem);
            tasks.Add(task);
            task.ContinueWith(t => mySemaphore.Release());           
        }

        await Task.WhenAll(tasks);
    }

    private async Task RunOperation<T>(T myItem)
    {
        // Do stuff
    }
public异步任务RunMultipleAsync(IEnumerable myList)
{
const int myNumberOfConcurrentOperations=10;
var mySemaphore=新信号量lim(myNumberOfConcurrentOperations);
var tasks=新列表();
foreach(myList中的var myItem)
{
等待mySemaphore.WaitAsync();
var任务=运行操作(myItem);
任务。添加(任务);
task.ContinueWith(t=>mySemaphore.Release());
}
等待任务。何时(任务);
}
专用异步任务运行操作(T myItem)
{
//做事
}
DownloadAttachmentsAsync
中的代码放在“Do stuff”注释处

这将使用信号量来限制并发操作的数量,因为运行多个并发操作通常是一个糟糕的ide
    public async Task RunMultipleAsync<T>(IEnumerable<T> myList)
    {
        const int myNumberOfConcurrentOperations = 10;
        var mySemaphore = new SemaphoreSlim(myNumberOfConcurrentOperations);
        var tasks = new List<Task>();
        foreach(var myItem in myList)
        {
            await mySemaphore.WaitAsync();
            var task = RunOperation(myItem);
            tasks.Add(task);
            task.ContinueWith(t => mySemaphore.Release());           
        }

        await Task.WhenAll(tasks);
    }

    private async Task RunOperation<T>(T myItem)
    {
        // Do stuff
    }