异步 Azure 文件存储 - 上传任务等待其他任务
Async Azure File Storage - Upload Tasks Wait For Other Tasks
我有这段异步运行委托的代码:
public delegate void FileHandler(string path);
....
FileHandler fileHandler = HandleFile;
foreach (FileInfo file in files)
{
string filePath = file.FullName;
if (IO.FileAvailable(filePath))
{
fileHandler.BeginInvoke(filePath, null, null); // i call EndInvoke later
}
}
这是委托,它只是将内容上传到 Azure 文件存储:
private static void HandleFile(string path)
{
AzureStorage.Instance.UploadFile("some-key", path);
}
此外,这是上传功能:
public async Task UploadFileAsync(string storageKey, string filePath)
{
CloudFile loc = Navigate(storageKey);
await TransferManager.UploadAsync(filePath, loc);
}
public void UploadFile(string storageKey, string filePath)
{
Task uploadTask = UploadFileAsync(storageKey, filePath);
Console.WriteLine("Will wait for " + storageKey + " path: " + filePath + " with thread: " + Thread.CurrentThread.ManagedThreadId);
uploadTask.Wait();
Console.WriteLine(">>> Done waiting for " + storageKey + " path: " + filePath);
uploadTask.Dispose();
}
这是我的输出:
Will wait for /bills/test/SomePdfName_1.pdf path: C:\test\SomePdfName_1.pdf with thread: 4
Will wait for /bills/test/SomePdfName_6.pdf path: C:\test\SomePdfName_6.pdf with thread: 7
Will wait for /bills/test/SomePdfName_10.pdf path: C:\test\SomePdfName_10.pdf with thread: 5
Will wait for /bills/test/SomePdfName_5.pdf path: C:\test\SomePdfName_5.pdf with thread: 9
Will wait for /bills/test/SomePdfName_3.pdf path: C:\test\SomePdfName_3.pdf with thread: 8
Will wait for /bills/test/SomePdfName_7.pdf path: C:\test\SomePdfName_7.pdf with thread: 11
Will wait for /bills/test/SomePdfName_4.pdf path: C:\test\SomePdfName_4.pdf with thread: 10
Will wait for /bills/test/SomePdfName_2.pdf path: C:\test\SomePdfName_2.pdf with thread: 6
Will wait for /bills/test/SomePdfName_8.pdf path: C:\test\SomePdfName_8.pdf with thread: 12
Will wait for /bills/test/SomePdfName_9.pdf path: C:\test\SomePdfName_9.pdf with thread: 13
.... 10 seconds later
>>> Done waiting for /bills/test/SomePdfName_9.pdf path: C:\test\SomePdfName_9.pdf
>>> Done waiting for /bills/test/SomePdfName_10.pdf path: C:\test\SomePdfName_10.pdf
>>> Done waiting for /bills/test/SomePdfName_1.pdf path: C:\test\SomePdfName_1.pdf
>>> Done waiting for /bills/test/SomePdfName_7.pdf path: C:\test\SomePdfName_7.pdf
>>> Done waiting for /bills/test/SomePdfName_2.pdf path: C:\test\SomePdfName_2.pdf
>>> Done waiting for /bills/test/SomePdfName_5.pdf path: C:\test\SomePdfName_5.pdf
>>> Done waiting for /bills/test/SomePdfName_6.pdf path: C:\test\SomePdfName_6.pdf
>>> Done waiting for /bills/test/SomePdfName_8.pdf path: C:\test\SomePdfName_8.pdf
>>> Done waiting for /bills/test/SomePdfName_3.pdf path: C:\test\SomePdfName_3.pdf
>>> Done waiting for /bills/test/SomePdfName_4.pdf path: C:\test\SomePdfName_4.pdf
如您所见,所有 10 个任务都必须先进入 Wait,然后才能完成任何上传任务? 我的问题是为什么?这对于 5、10、100 或 1000 个文件都是一样的。
As you see, all 10 tasks have to enter into Wait first, before any of the upload tasks finish? My question why is that? This is the same either with 5, 10, 100 or 1000 files.
在我看来,这个操作我觉得应该分两种情况。
第一个。您上传的文件没有超过线程池数量
由于每个BeginInvoke操作都会在线程池中选择一个线程来执行UploadFile方法(所有操作都是异步的)并且await TransferManager.UploadAsync会花费很多时间来上传文件,所以你会发现,好像是等所有任务完成再开始上传。
实际上一个线程不会影响另一个线程,只是线程执行得很快。
其次,如果应用程序使用的线程数超过当前线程池数。
进程线程池的默认大小取决于几个因素,例如虚拟地址的大小space。线程数超过了当前线程池的线程数。它不会立即创建新线程全部 situations.It 如果有未完成的任务,将每 0.5 秒创建一个线程,直到最大线程数。
所以你会发现应用程序首先创建足够的线程来 运行 UploadFile 看起来像在等待 first.In 我认为,没有足够的线程来执行 await TransferManager.UploadAsync 方法(这会从线程池中获取另一个线程运行它)。由于 运行ning 上传线程的优先级高于 await TransferManager.UploadAsync 线程。所以计算机会首先创建新线程到运行 UploadFile 方法。如果所有 UploadFile 方法 运行 完全,那么它将分配另一个线程给 运行 TransferManager.UploadAsync 方法。
如果您希望您的应用程序不等待所有任务,您可以尝试使用并行 class。
更多细节,你可以参考这段代码:
Parallel.ForEach(dirInfo.GetFiles(), new ParallelOptions() { MaxDegreeOfParallelism = 108 }, (file) =>
{
string filePath = file.FullName;
Console.WriteLine("start BeginInvoke for file: " + file + " with thread: " + Thread.CurrentThread.ManagedThreadId);
fileHandler.Invoke(filePath); // i call EndInvoke later
Console.WriteLine("end BeginInvoke for file: " + file + " with thread: " + Thread.CurrentThread.ManagedThreadId);
});
我有这段异步运行委托的代码:
public delegate void FileHandler(string path);
....
FileHandler fileHandler = HandleFile;
foreach (FileInfo file in files)
{
string filePath = file.FullName;
if (IO.FileAvailable(filePath))
{
fileHandler.BeginInvoke(filePath, null, null); // i call EndInvoke later
}
}
这是委托,它只是将内容上传到 Azure 文件存储:
private static void HandleFile(string path)
{
AzureStorage.Instance.UploadFile("some-key", path);
}
此外,这是上传功能:
public async Task UploadFileAsync(string storageKey, string filePath)
{
CloudFile loc = Navigate(storageKey);
await TransferManager.UploadAsync(filePath, loc);
}
public void UploadFile(string storageKey, string filePath)
{
Task uploadTask = UploadFileAsync(storageKey, filePath);
Console.WriteLine("Will wait for " + storageKey + " path: " + filePath + " with thread: " + Thread.CurrentThread.ManagedThreadId);
uploadTask.Wait();
Console.WriteLine(">>> Done waiting for " + storageKey + " path: " + filePath);
uploadTask.Dispose();
}
这是我的输出:
Will wait for /bills/test/SomePdfName_1.pdf path: C:\test\SomePdfName_1.pdf with thread: 4
Will wait for /bills/test/SomePdfName_6.pdf path: C:\test\SomePdfName_6.pdf with thread: 7
Will wait for /bills/test/SomePdfName_10.pdf path: C:\test\SomePdfName_10.pdf with thread: 5
Will wait for /bills/test/SomePdfName_5.pdf path: C:\test\SomePdfName_5.pdf with thread: 9
Will wait for /bills/test/SomePdfName_3.pdf path: C:\test\SomePdfName_3.pdf with thread: 8
Will wait for /bills/test/SomePdfName_7.pdf path: C:\test\SomePdfName_7.pdf with thread: 11
Will wait for /bills/test/SomePdfName_4.pdf path: C:\test\SomePdfName_4.pdf with thread: 10
Will wait for /bills/test/SomePdfName_2.pdf path: C:\test\SomePdfName_2.pdf with thread: 6
Will wait for /bills/test/SomePdfName_8.pdf path: C:\test\SomePdfName_8.pdf with thread: 12
Will wait for /bills/test/SomePdfName_9.pdf path: C:\test\SomePdfName_9.pdf with thread: 13
.... 10 seconds later
>>> Done waiting for /bills/test/SomePdfName_9.pdf path: C:\test\SomePdfName_9.pdf
>>> Done waiting for /bills/test/SomePdfName_10.pdf path: C:\test\SomePdfName_10.pdf
>>> Done waiting for /bills/test/SomePdfName_1.pdf path: C:\test\SomePdfName_1.pdf
>>> Done waiting for /bills/test/SomePdfName_7.pdf path: C:\test\SomePdfName_7.pdf
>>> Done waiting for /bills/test/SomePdfName_2.pdf path: C:\test\SomePdfName_2.pdf
>>> Done waiting for /bills/test/SomePdfName_5.pdf path: C:\test\SomePdfName_5.pdf
>>> Done waiting for /bills/test/SomePdfName_6.pdf path: C:\test\SomePdfName_6.pdf
>>> Done waiting for /bills/test/SomePdfName_8.pdf path: C:\test\SomePdfName_8.pdf
>>> Done waiting for /bills/test/SomePdfName_3.pdf path: C:\test\SomePdfName_3.pdf
>>> Done waiting for /bills/test/SomePdfName_4.pdf path: C:\test\SomePdfName_4.pdf
如您所见,所有 10 个任务都必须先进入 Wait,然后才能完成任何上传任务? 我的问题是为什么?这对于 5、10、100 或 1000 个文件都是一样的。
As you see, all 10 tasks have to enter into Wait first, before any of the upload tasks finish? My question why is that? This is the same either with 5, 10, 100 or 1000 files.
在我看来,这个操作我觉得应该分两种情况。
第一个。您上传的文件没有超过线程池数量
由于每个BeginInvoke操作都会在线程池中选择一个线程来执行UploadFile方法(所有操作都是异步的)并且await TransferManager.UploadAsync会花费很多时间来上传文件,所以你会发现,好像是等所有任务完成再开始上传。
实际上一个线程不会影响另一个线程,只是线程执行得很快。
其次,如果应用程序使用的线程数超过当前线程池数。
进程线程池的默认大小取决于几个因素,例如虚拟地址的大小space。线程数超过了当前线程池的线程数。它不会立即创建新线程全部 situations.It 如果有未完成的任务,将每 0.5 秒创建一个线程,直到最大线程数。
所以你会发现应用程序首先创建足够的线程来 运行 UploadFile 看起来像在等待 first.In 我认为,没有足够的线程来执行 await TransferManager.UploadAsync 方法(这会从线程池中获取另一个线程运行它)。由于 运行ning 上传线程的优先级高于 await TransferManager.UploadAsync 线程。所以计算机会首先创建新线程到运行 UploadFile 方法。如果所有 UploadFile 方法 运行 完全,那么它将分配另一个线程给 运行 TransferManager.UploadAsync 方法。
如果您希望您的应用程序不等待所有任务,您可以尝试使用并行 class。
更多细节,你可以参考这段代码:
Parallel.ForEach(dirInfo.GetFiles(), new ParallelOptions() { MaxDegreeOfParallelism = 108 }, (file) =>
{
string filePath = file.FullName;
Console.WriteLine("start BeginInvoke for file: " + file + " with thread: " + Thread.CurrentThread.ManagedThreadId);
fileHandler.Invoke(filePath); // i call EndInvoke later
Console.WriteLine("end BeginInvoke for file: " + file + " with thread: " + Thread.CurrentThread.ManagedThreadId);
});