在新任务 c# 中调用异步方法
Call async method in new task c#
我正在尝试解决的问题:
对于每个目录,它存在一些文件,我想把它上传到Azure。
所以我想这样做:
任务 1 - 将目录 1 中的文件上传到 azure
任务 2 - 将目录 2 中的文件上传到 azure
我想同时做这个。
我有以下代码:
private async Task ProcessMatFiles(string directory, List<FileInfo> matFiles)
{
foreach (var file in matFiles)
{
if (!string.IsNullOrEmpty(file.Name) && !string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(file.FullName))
{
var cloudBlockBlob = this._cloudBlobContainer.GetBlockBlobReference("textures/" + directory + "/" + file.Name);
if (!await cloudBlockBlob.ExistsAsync())
await cloudBlockBlob.UploadFromFileAsync(file.FullName);
}
}
List<Task> tasks = new List<Task>();
foreach (var directory in matFileDirectories)
{
// Get all the files in the directory
var matFiles = new DirectoryInfo(directory).EnumerateFiles().ToList();
// Get the directory name of the files
var matDirectory = Path.GetFileName(Path.GetDirectoryName(matFiles.FirstOrDefault().FullName));
if (matFiles.Count > 0 && !string.IsNullOrEmpty(matDirectory))
{
var task = new Task(() =>this.ProcessMatFiles(matDirectory, matFiles));
tasks.Add(task);
task.Start();
}
}
Task.WaitAll(tasks.ToArray());
使用此代码,我收到以下警告:
Because this call is not awaited, execution of the current method
continues before the call is completed. Consider applying the 'await'
operator to the result of the call.
这是什么意思?这对我的代码有何影响?
我可以这样删除警告:
var task = new Task(async () => await this.ProcessMatFiles());
这是正确的方法吗?
真正的问题似乎是如何并行处理多个文件。 ProcessMatFiles
returns 已经 Task
我认为它不会 运行 调用者线程上的任何内容。该任务可以存储在 tasks
列表中。可以等待该列表而不会阻塞
await Task.WhenAll(tasks);
更好的解决方案是将整个循环转换为 returns 任务的 LINQ 查询并等待它。
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
let files=dir.GetFiles()
select ProcessMatFiles(dir.Name, files));
await Task.WhenAll(tasks);
这样做的问题是枚举文件夹中的文件本身就很昂贵,并且GetFiles()
或使用EnumerateFiles().ToList()
必须等待枚举完成。如果 ProcessMatFiles
收到 DirectoryInfo 对象并在单独的线程 中枚举文件 .
会更好
另一个改进是逐个处理文件:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select ProcessMatFile(dir.Name, file));
如果知道 ProcessMatFiles
的作用,则可以进一步改进这一点,例如使用数据流块或通道进行节流并使用特定数量的任务,将流程分解为多个并发步骤等。
更新
由于这是一个文件上传操作,每个文件都是一个单独的异步操作。使用 DirectoryInfo 和 FileInfo 对象时,可以删除大部分检查。
上传方法应该是:
async Task Upload(FileInfo file)
{
var folder=file.Directory.Name;
var blob = _cloudBlobContainer.GetBlockBlobReference(${"textures/{folder}/{file.Name}";
if (!await blob.ExistsAsync())
{
await blob.UploadFromFileAsync(file.FullName);
}
}
任务生成查询可以简化为:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select UploadFile(file);
await Task.WhenAll(tasks);
这将尝试以与文件迭代一样快的速度触发所有上传操作。这可能会淹没网络。一种解决方案是使用 ActionBlock 一次仅使用 8 个任务来上传文件。输入缓冲区也有限制,以避免用例如 1000 个 FileInfo 项填充它:
var options=new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 8, //Only 8 concurrent operations
BoundedCapacity=64 //Block posters if the input buffer has too many items
} ;
var block=new ActionBlock<FileInfo>(async file=>UploadFile(file),options);
var files = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select file;
foreach(var file in files)
{
//Wait here if the input buffer is full
await block.SendAsync(file);
}
block.Complete();
//Wait for all uploads to finish
await block.Completion;
我正在尝试解决的问题:
对于每个目录,它存在一些文件,我想把它上传到Azure。
所以我想这样做: 任务 1 - 将目录 1 中的文件上传到 azure 任务 2 - 将目录 2 中的文件上传到 azure
我想同时做这个。
我有以下代码:
private async Task ProcessMatFiles(string directory, List<FileInfo> matFiles)
{
foreach (var file in matFiles)
{
if (!string.IsNullOrEmpty(file.Name) && !string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(file.FullName))
{
var cloudBlockBlob = this._cloudBlobContainer.GetBlockBlobReference("textures/" + directory + "/" + file.Name);
if (!await cloudBlockBlob.ExistsAsync())
await cloudBlockBlob.UploadFromFileAsync(file.FullName);
}
}
List<Task> tasks = new List<Task>();
foreach (var directory in matFileDirectories)
{
// Get all the files in the directory
var matFiles = new DirectoryInfo(directory).EnumerateFiles().ToList();
// Get the directory name of the files
var matDirectory = Path.GetFileName(Path.GetDirectoryName(matFiles.FirstOrDefault().FullName));
if (matFiles.Count > 0 && !string.IsNullOrEmpty(matDirectory))
{
var task = new Task(() =>this.ProcessMatFiles(matDirectory, matFiles));
tasks.Add(task);
task.Start();
}
}
Task.WaitAll(tasks.ToArray());
使用此代码,我收到以下警告:
Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
这是什么意思?这对我的代码有何影响?
我可以这样删除警告:
var task = new Task(async () => await this.ProcessMatFiles());
这是正确的方法吗?
真正的问题似乎是如何并行处理多个文件。 ProcessMatFiles
returns 已经 Task
我认为它不会 运行 调用者线程上的任何内容。该任务可以存储在 tasks
列表中。可以等待该列表而不会阻塞
await Task.WhenAll(tasks);
更好的解决方案是将整个循环转换为 returns 任务的 LINQ 查询并等待它。
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
let files=dir.GetFiles()
select ProcessMatFiles(dir.Name, files));
await Task.WhenAll(tasks);
这样做的问题是枚举文件夹中的文件本身就很昂贵,并且GetFiles()
或使用EnumerateFiles().ToList()
必须等待枚举完成。如果 ProcessMatFiles
收到 DirectoryInfo 对象并在单独的线程 中枚举文件 .
另一个改进是逐个处理文件:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select ProcessMatFile(dir.Name, file));
如果知道 ProcessMatFiles
的作用,则可以进一步改进这一点,例如使用数据流块或通道进行节流并使用特定数量的任务,将流程分解为多个并发步骤等。
更新
由于这是一个文件上传操作,每个文件都是一个单独的异步操作。使用 DirectoryInfo 和 FileInfo 对象时,可以删除大部分检查。
上传方法应该是:
async Task Upload(FileInfo file)
{
var folder=file.Directory.Name;
var blob = _cloudBlobContainer.GetBlockBlobReference(${"textures/{folder}/{file.Name}";
if (!await blob.ExistsAsync())
{
await blob.UploadFromFileAsync(file.FullName);
}
}
任务生成查询可以简化为:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select UploadFile(file);
await Task.WhenAll(tasks);
这将尝试以与文件迭代一样快的速度触发所有上传操作。这可能会淹没网络。一种解决方案是使用 ActionBlock 一次仅使用 8 个任务来上传文件。输入缓冲区也有限制,以避免用例如 1000 个 FileInfo 项填充它:
var options=new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 8, //Only 8 concurrent operations
BoundedCapacity=64 //Block posters if the input buffer has too many items
} ;
var block=new ActionBlock<FileInfo>(async file=>UploadFile(file),options);
var files = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select file;
foreach(var file in files)
{
//Wait here if the input buffer is full
await block.SendAsync(file);
}
block.Complete();
//Wait for all uploads to finish
await block.Completion;