如何在相关集合之间添加异步切换C#
我有项目需要通过id从数据库中收集文件,将这些文件压缩起来,将压缩文件上传到第三方Web服务,并对响应进行一些操作。我正在使用Parallel.ForEach来尝试完成此操作,但我无法使其异步运行,而且我甚至不确定这是实现此目的的最佳方式。有没有办法异步运行,并更有效?如何在相关集合之间添加异步切换C#
public async Task<string> UploadZip(string courseID)
{
string result = string.empty;
ids = courseID.Split(',').ToList();
ConcurrentStack<string> zipPaths = new ConcurrentStack<string>();
Parallel.ForEach(ids, (id) =>
{
files = rep.GetFiles(id);
ZipFiles zf = new ZipFile(files);
zipPaths.Push(zf.ZipFilePath);
try
{
while (zipPaths.Count > 0)
{
FileHolder fh;
if (fileHolder.TryPop(out fh))
{
FileInfo file = new FileInfo(fh.EndPoint);
if (file != null && file.Length > 0)
{
// string fileName = Path.GetFileName(path);
result = CallService(zf.PathToZip);
DoSomethingElse oSomethingElse = new DoSomethingElse(result, id, version);
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(string.Concat("HomeController line 123","error ",ex.Message, DateTime.Now.TimeOfDay));
}
ITermExtractorContent result = new TermExtractorContent();
});
return output;
}
private static async Task<string> CallService(string pathToZip)
{
using (var client = new HttpClient())
{
//headers for client
try
{
using (var content = new MultipartFormDataContent())
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var fileContent = new StreamContent(stream))
{
fileContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\"");
content.Add(fileContent, "file", Path.GetFileName(pathToZip));
using (
var message =
await client.PostAsync(baseEndpoint, content))
{
output = await message.Content.ReadAsStringAsync();
}
}
}
}//end using
}
catch (Exception ex)
{
log(ex);
}
}// using (var client = new HttpClient())
return output;
}
我看到这需要异步的唯一原因是为了防止阻塞UI线程。我不确定DoSomethingElse()
会做什么(这是您尝试同时运行的方法吗?)以及如何使用结果变量作为参数,但我觉得上面的行result = CallService(zf.PathToZip);
应该是result = await CallService(zf.PathToZip);
由于当前函数被标记为异步它会通知编译器创建一个回调,以便在任务返回时执行,并在那里恢复执行。当你的程序碰到该方法时,它将不会继续执行,直到它被返回。其他线程(如称为异步方法的线程)将继续执行。给你打电话UploadZip()
方法将它使用类似:因为这
public void DoThings()
{
UploadZip("MyString");
DoSomethingElseConcurrently();
}
也请记住线程安全(竞争条件,死锁等)是异步编程。在这里使用TPL时会遇到一些小问题,因为您可能会发现自己嵌套了异步方法调用(就像您在此处所做的那样)。外部异步调用不能使用.Result()
方法,因为它阻止该线程。内部异步线程将尝试返回到调用它的方法,从而进入死锁。
我在UI中使用了一个进度条,所以我肯定不想阻止它。 – user2049142
没有理由使用Async进行CPU绑定操作。异步基本上是一种防止线程在等待外部源时无所事事的方式。你的代码做了很多工作,完全是一个线程。 –
我看到你的第一个方法没有任何await关键字;这意味着你的代码并不是异步的。你必须得到一个编译器警告,说明一样。 –
@ErikPhilips但我想有两个进程1.one用于获取文件和压缩它们2.另一个用于压缩文件,上传,等待响应。除非我错了,否则应比2少花时间 - 因此基本上需要两个线程。 – user2049142