下面的代码片段有什么区别?两个都不会使用线程池线程吗?
例如,如果我想为集合中的每个项目调用一个函数,
Parallel.ForEach<Item>(items, item => DoSomething(item));
vs
foreach(var item in items)
{
Task.Factory.StartNew(() => DoSomething(item));
}
Run Code Online (Sandbox Code Playgroud) 我试图理解为什么ASP.Net应用程序中的异步void方法可能导致以下异常,而async Task似乎不会:
System.InvalidOperationException: An asynchronous module or handler
completed while an asynchronous operation was still pending
Run Code Online (Sandbox Code Playgroud)
我对.NET中的异步世界相对较新,但我觉得我试图通过一些现有资源来运行这个,包括以下所有内容:
从这些资源中,我了解最佳做法是通常返回Task并避免异步void.我也理解async void会在调用方法时增加未完成操作的数量,并在完成时减少它.这听起来至少是我问题答案的一部分.但是,我遗漏的是当我返回Task时会发生什么,以及为什么这样做会让事情变得"有效".
这是一个人为的例子来进一步说明我的问题:
public class HomeController : AsyncController
{
// This method will work fine
public async Task<ActionResult> ThisPageWillLoad()
{
// Do not await the task since it is meant to be fire and forget
var task = this.FireAndForgetTask();
return await Task.FromResult(this.View("Index"));
}
private async Task FireAndForgetTask()
{
var task = Task.Delay(TimeSpan.FromSeconds(3));
await task;
}
// This …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用新任务,但发生了一些我不明白的事情.
首先,代码非常简单.我传入一些图像文件的路径列表,并尝试添加一个任务来处理它们中的每一个:
public Boolean AddPictures(IList<string> paths)
{
Boolean result = (paths.Count > 0);
List<Task> tasks = new List<Task>(paths.Count);
foreach (string path in paths)
{
var task = Task.Factory.StartNew(() =>
{
Boolean taskResult = ProcessPicture(path);
return taskResult;
});
task.ContinueWith(t => result &= t.Result);
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
return result;
}
Run Code Online (Sandbox Code Playgroud)
我发现,如果我让它运行,例如,单元测试中的3个路径列表,则所有三个任务都使用提供列表中的最后一个路径.如果我单步执行(并减慢循环的处理速度),则使用循环中的每个路径.
有人可以解释一下发生了什么,为什么?可能的解决方法?
在这个答案中,https: //stackoverflow.com/a/8649429/1497 Eric Lippert说"我们很有可能在下一版本的C#中解决这个问题;对于开发人员而言,这是一个主要的痛点". foreach循环使用变量.
在下一个版本中,每次运行"foreach"循环时,我们将生成一个新的循环变量,而不是每次都关闭相同的变量.这是一个"突破"的变化,但在绝大多数情况下,"休息"将是修复而不是导致错误.
我无法找到任何表明此更改尚未完成的内容.有没有迹象表明这是foreach循环在C#5中的工作方式?
我有这样的方法:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
foreach(var method in Methods)
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后我决定使用Parallel.ForEach:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
Parallel.ForEach(Methods, async method =>
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
});
return result;
}
Run Code Online (Sandbox Code Playgroud)
但现在我有一个错误:
在异步操作仍处于挂起状态时完成异步模块或处理程序.
我试图并行运行3个db查询,但我不确定我是否正确执行.
我已经创建了3个函数,每个函数都对db进行查询.
private static async Task<string> getAccountCodeAsync(string deviceId)
{
long deviceIdLong = long.Parse(deviceId);
using (var db = new NetworksEntities())
{
return db.Devices.Where(x => x.DeviceId == deviceIdLong)
.Select(x => x.AccountCode)
.FirstOrDefault();
}
}
private static async Task<string> getDeviceTypeAsync(string deviceId)
{
long deviceIdLong = long.Parse(deviceId);
using (var db = new NetworksEntities())
{
return db.Devices.Where(x => x.DeviceId == deviceIdLong)
.Select(x => x.DeviceType)
.FirstOrDefault()
.DeviceType;
}
}
private static async Task<string> getUserNameAsync(string userId)
{
int userIdInt;
Int32.TryParse(userId, out userIdInt);
using (var db = new …Run Code Online (Sandbox Code Playgroud) c# asp.net multithreading asynchronous task-parallel-library
我已经切换到某些项目的.net Core,现在我遇到了Parallel.ForEach的问题.在过去,我经常有一个id值列表,然后我将用它来发送Web请求以获取完整数据.它看起来像这样:
Parallel.ForEach(myList, l =>
{
// make web request using l.id
// process the data somehow
});
Run Code Online (Sandbox Code Playgroud)
好吧,在.net Core中,必须标记所有Web请求await,这意味着必须标记Parallel.ForEach操作async.但是,将Parallel.ForEach操作标记为async意味着我们有一个void async导致问题的方法.在我的特定情况下,这意味着响应在并行循环中的所有Web请求完成之前返回到应用程序,这既尴尬又导致错误.
问题:在这里使用Parallel.ForEach的替代方法是什么?
我发现一个可能的解决方案是将Parallel循环包装在Task中并等待任务:
await Task.Run(() => Parallel.ForEach(myList, l =>
{
// stuff here
}));
Run Code Online (Sandbox Code Playgroud)
(在这里找到:Parallel.ForEach vs Task.Run和Task.WhenAll)
但是,这对我不起作用.当我使用它时,我仍然在循环完成之前返回应用程序.
另外一个选项:
var tasks = new List<Task>();
foreach (var l in myList)
{
tasks.Add(Task.Run(async () =>
{
// stuff here
}));
}
await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但这是唯一的选择吗?似乎新的.net Core已经使Parallel.ForEach几乎无用(至少在嵌套Web调用时).
任何帮助/建议表示赞赏.
我正试图找出使用Task和并行化HTTP请求的正确方法async/await.我正在使用HttpClient已经具有异步方法来检索数据的类.如果我只是在foreach循环中调用它并等待响应,则一次只发送一个请求(这是有道理的,因为在await控制期间,控制返回到我们的事件循环,而不是foreach循环的下一次迭代).
我的包装HttpClient看起来像这样
public sealed class RestClient
{
private readonly HttpClient client;
public RestClient(string baseUrl)
{
var baseUri = new Uri(baseUrl);
client = new HttpClient
{
BaseAddress = baseUri
};
}
public async Task<Stream> GetResponseStreamAsync(string uri)
{
var resp = await GetResponseAsync(uri);
return await resp.Content.ReadAsStreamAsync();
}
public async Task<HttpResponseMessage> GetResponseAsync(string uri)
{
var resp = await client.GetAsync(uri);
if (!resp.IsSuccessStatusCode)
{
// ...
}
return resp;
}
public async Task<T> GetResponseObjectAsync<T>(string uri) …Run Code Online (Sandbox Code Playgroud) 我已阅读以下密切相关的主题,但我想问一个更具体的事情。
如果我们需要异步运行任务/方法,并且这些任务本身运行其他任务/等待其他任务,则首选哪种变体 - Parallel.ForEach,或Task.WhenAll?我将用下面的一些代码进行演示:
public async Task SomeWorker(string param1, HttpClient client,
List<FillMeUp> emptyCollection)
{
HttpRequestMessage message = new HttpRequestMessage();
message.Method = HttpMethod.Get;
message.Headers.Add("someParam", param1);
message.RequestUri = new Uri("https://www.somesite.me");
var requestResponse = await client.SendAsync(message).ConfigureAwait(false);
var content = await requestResponse.Content.ReadAsStringAsync()
.ConfigureAwait(false);
emptyCollection.Add(new FillMeUp()
{
Param1 = param1
});
}
Run Code Online (Sandbox Code Playgroud)
与 一起使用WhenAll:
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Accept", "application/json");
List<FullCollection> fullCollection = GetMyFullCollection();
List<FillMeUp> emptyCollection = new List<FillMeUp>();
List<Task> workers = new List<Task>();
for …Run Code Online (Sandbox Code Playgroud) 基于这个问题,我正在尝试设置代码以将多个图像并行保存到Azure Blob存储.下面这个方法工作正常,等待Task.WhenAll(任务)等待所有人完成后再继续.
唯一的麻烦是,我希望能够找出每个在我们的数据库中存储信息的请求是否真的成功了._db.AddImageAsync返回一个bool,下面的代码等待所有任务完成,但是当我检查所有任务的结果时,每个都是假的(即使我在括号内实际返回true).
Enumerable中的每个任务都表示,即使我逐步执行断点并且每个任务都已执行,结果仍未计算.
var tasks = wantedSizes.Select(async (wantedSize, index) =>
{
var resize = size.CalculateResize(wantedSize.GetMaxSize());
var quality = wantedSize.GetQuality();
using (var output = ImageProcessHelper.Process(streams[index], resize, quality))
{
var path = await AzureBlobHelper.SaveFileAsync(output, FileType.Image);
var result = await _db.AddImageAsync(id, wantedSize, imageNumber, path);
return result;
}
});
await Task.WhenAll(tasks)
if (!tasks.All(task => task.Result))
return new ApiResponse(ResponseStatus.Fail);
Run Code Online (Sandbox Code Playgroud)
任何帮助深表感谢!
我有一个异步调用 ( DoAsyncWork()),我想以一种即发即弃的方式开始,即我对它的结果不感兴趣,并且希望调用线程在异步方法完成之前继续。
这样做的正确方法是什么?我在 .NET Framework 4.6 和 .NETCore 2 中都需要这个,以防有差异。
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
Run Code Online (Sandbox Code Playgroud)
它是这两者之一还是不同/更好的东西?
//编辑:理想情况下没有任何额外的库。
我有一个使用MEF加载插件的应用程序.所有这些插件都符合以下界面:
public interface IPlugin {
Task Start();
}
Run Code Online (Sandbox Code Playgroud)
所有方法都实现为async:public async Task Start()
当应用程序运行时,我有一个IEnumerable<IPlugin>可用于所有插件的属性.问题基本上是我如何Start()并行运行所有方法并等待所有方法完成?
我知道Parallel.ForEach(plugins, plugin => plugin.Start()),但这是不可能的,并且在所有插件启动之前执行仍在继续.
最有希望的解决方案似乎是Task.WhenAll(),但我不知道如何在不添加一些脚手架(这似乎是开销)的情况下将未知的方法列表发送到此.
我怎么能做到这一点?
c# ×12
async-await ×7
.net ×3
asp.net ×3
.net-core ×2
asynchronous ×2
.net-4.5 ×1
c#-4.0 ×1
c#-5.0 ×1
concurrency ×1
foreach ×1
task ×1