C# 如何在相关集合C之间添加异步切换#
我有一个项目,我需要通过id从数据库收集文件,压缩这些文件,将压缩后的文件上传到第三方web服务,并对响应进行处理。我正在使用Parallel.ForEach来尝试并实现这一点,但在异步运行时遇到了问题,我甚至不确定这是否是实现这一点的最佳方法。有没有一种方法可以更高效地异步运行C# 如何在相关集合C之间添加异步切换#,c#,.net,asynchronous,C#,.net,Asynchronous,我有一个项目,我需要通过id从数据库收集文件,压缩这些文件,将压缩后的文件上传到第三方web服务,并对响应进行处理。我正在使用Parallel.ForEach来尝试并实现这一点,但在异步运行时遇到了问题,我甚至不确定这是否是实现这一点的最佳方法。有没有一种方法可以更高效地异步运行 public async Task<string> UploadZip(string courseID) { string result = string.empty;
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;
}
public async Task UploadZip(字符串courseID)
{
字符串结果=string.empty;
ids=courseID.Split(',).ToList();
ConcurrentStack zipPaths=新的ConcurrentStack();
Parallel.ForEach(id,(id)=>
{
files=rep.GetFiles(id);
ZipFile zf=新ZipFile(文件);
zipPaths.Push(zf.ZipFilePath);
尝试
{
而(zipPaths.Count>0)
{
文件持有人fh;
if(文件持有者.TryPop(输出fh))
{
FileInfo file=新的FileInfo(fh.EndPoint);
if(file!=null&&file.Length>0)
{
//字符串fileName=Path.GetFileName(Path);
结果=调用服务(zf.PathToZip);
DoSomethingElse-oSomethingElse=新的DoSomethingElse(结果、id、版本);
}
}
}
}
捕获(例外情况除外)
{
System.Diagnostics.Debug.WriteLine(string.Concat(“HomeController行123”,“错误”,例如Message,DateTime.Now.TimeOfDay));
}
ITermExtractorContent结果=新术语extractorcontent();
});
返回输出;
}
专用静态异步任务调用服务(字符串pathToZip)
{
使用(var client=new HttpClient())
{
//客户端的标题
尝试
{
使用(var content=new MultipartFormDataContent())
{
使用(var stream=newfilestream(路径,FileMode.Open,FileAccess.Read,FileShare.ReadWrite))
{
使用(var fileContent=newstreamcontent(流))
{
fileContent.Headers.Add(“内容处置”,“表单数据;名称=\”文件\“,”文件名=\”+路径.GetFileName(路径)+“\”);
Add(fileContent,“file”,Path.GetFileName(pathToZip));
使用(
var消息=
等待client.PostAsync(baseEndpoint,content))
{
output=wait message.Content.ReadAsStringAsync();
}
}
}
}//终端使用
}
捕获(例外情况除外)
{
对数(ex);
}
}//使用(var client=new HttpClient())
返回输出;
}
我认为这需要异步的唯一原因是为了防止阻塞UI线程。我不确定DoSomethingElse()
是做什么的(这是您试图同时运行的方法吗?)以及如何使用结果变量作为参数,但我觉得上面的一行result=CallService(zf.PathToZip)
应该是result=await CallService(zf.PathToZip)
由于当前函数标记为async,它将向编译器发出信号,在任务返回时创建要执行的回调,并将在那里继续执行。当您的程序点击该方法时,它将不会继续执行,直到返回为止。其他线程(如调用异步方法的线程)将继续执行。要调用您的UploadZip()
方法,可以使用如下方法:
public void DoThings()
{
UploadZip("MyString");
DoSomethingElseConcurrently();
}
还请记住线程安全(竞争条件、死锁等),因为这是异步编程。在这里使用TPL时有一些小问题,因为您可能会发现自己嵌套了异步方法调用(就像您在这里所做的那样)。外部异步调用不能使用
.Result()
方法,因为它会阻止该线程。内部异步线程将尝试返回调用它的方法,从而进入死锁。没有理由对CPU绑定的操作使用异步。异步基本上是一种防止线程在等待外部源时无所事事的方法。你的代码做了很多工作,这正是线程的用途;这意味着您的代码不是真正的异步。您一定收到了一个编译器警告,说明了相同的情况。@ErikPhilips,但我希望有两个进程1。一个用于获取文件并对其进行压缩2。而另一个则采取压缩文件,上传,等待响应。除非我错了,否则1所花的时间应该少于2,因此基本上需要两个线程。@SriramSakthivel这是正确的。我对.NET中的TPL非常陌生。我在UI中使用进度条,所以我肯定不想阻止它。