我不确定我的程序是否完全符合我的要求,或者它是否可以更好地编码。 目标是调用2个方法(CreateHeaderAsync,CombineFilesAsync)并让它们并行工作。
我不认为这是写这些的正确或好方法...... Async()方法,因为它看起来很不洁净。
并且我不能在我的CreateFile方法中结合前4行来减少不重要的代码并使其更具可读性?
public void CreateFile(string path)
{
Task<byte[]> headerTask = CreateHeaderAsync();
Task<byte[]> filesTask = CombineFilesAsync();
byte[] header = headerTask.Result;
byte[] files = filesTask.Result;
byte[] combined = new byte[header.Length + files.Length];
Buffer.BlockCopy(header, 0, combined, 0, header.Length);
Buffer.BlockCopy(files, 0, combined, header.Length, files.Length);
Task.Factory.StartNew(() => File.WriteAllBytes(path, combined));
}
private Task<byte[]> CreateHeaderAsync()
{
return Task.Factory.StartNew(() =>
{
StringBuilder sb = new StringBuilder();
int position = 0;
foreach (ByteFile file in _files)
{
sb.Append(file + "?" + position + Environment.NewLine);
position += file.Length;
}
return Encoding.UTF8.GetBytes(sb + "--header_end--" + Environment.NewLine);
});
}
private Task<byte[]> CombineFilesAsync()
{
return Task.Factory.StartNew(() =>
{
ByteFile[] arrays = _files.ToArray();
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (ByteFile t in arrays)
{
var array = Encryption.EncryptBytes(t.Content, "password");
Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
});
}
答案 0 :(得分:2)
目标是调用2个方法(CreateHeaderAsync,CombineFilesAsync)并让它们并行工作。
然后尝试Task.WhenAll以异步方式等待完成。
public async Task CreateFile(string path)
{
Task<byte[]> headerTask = CreateHeaderAsync();
Task<byte[]> filesTask = CombineFilesAsync();
var allResults = await Task.WhenAll(headerTask, filesTask);
byte[] header = allResults[0];
byte[] files = allResults[1];
回复到评论
他也不能做byte [] header = await headerTask; byte [] files = await filesTask;他等待一项任务是否重要,即使另一项任务可能在它之前完成?
确定。这是真的。唯一的问题是两个await
可以再次恢复呼叫者。所以我更喜欢单一的最终回调。
答案 1 :(得分:0)
如果您希望它们并行运行,您可以使用WhenAll。
https://msdn.microsoft.com/en-us/library/hh194874(v=vs.110).aspx
这样的事情:
public void CreateFile(string path)
{
Task<byte[]>[] tasks = new [] { CreateHeaderAsync(), CombineFilesAsync() };
var resultSet = Task.WhenAll(tasks); // create an aggregate task
try
{
resultSet.Wait(); // await the results
}
catch (AggregateException)
{
// handle exceptions in the tasks here
}
if (resultSet.Status == TaskStatus.RanToCompletion)
{
// get your results
byte[] header = resultSet.Result[0];
byte[] files = resultSet.Result[1];
byte[] combined = new byte[header.Length + files.Length];
Buffer.BlockCopy(header, 0, combined, 0, header.Length);
Buffer.BlockCopy(files, 0, combined, header.Length, files.Length);
Task.Factory.StartNew(() => File.WriteAllBytes(path, combined));
}
}
此外,在这种情况下,我会发现Task.Run()比Task.Factory.StartNew()更具可读性。
https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/
它允许您通过将所有任务集中在CreateFile方法中来使CreateHeaderAsync和CombineFilesAsync更小。
public void CreateFile(string path)
{
Task<byte[]>[] tasks = new [] {
Task.Run((byte[])CreateHeaderAsync),
Task.Run((byte[])CombineFilesAsync)};
// rest of the method
}
private byte[] CombineFilesAsync()
{
ByteFile[] arrays = _files.ToArray();
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (ByteFile t in arrays)
{
var array = Encryption.EncryptBytes(t.Content, "password");
Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
写得快一点,没有检查,如果有任何奇怪的错误在那里偷偷道歉:)
答案 2 :(得分:0)
我会选择异步/等待模式。使用Task.Result
会导致调用线程被阻塞,这在某些情况下会导致死锁。
如果您不想使用任务创建选项并且您不希望能够取消任务,我建议您使用Task.Run(() => {})
创建任务。在大多数情况下,这正是您所需要的。
因此,将您的异步方法签名更改为public async ...
,然后调用task.Result而不是等待任务:
var taskResult = await MyMethodAsync();