我有一些代码,我目前正在优化多核架构中的并发性.在我的一个类中,我发现了一个嵌套foreach循环.基本上,外部循环遍历一个NetworkInterface对象数组.内循环通过网络接口IP地址进行迭代.
它让我思考,嵌套Parallel.ForEach循环一定是个好主意吗?阅读本文后(同一列表上的嵌套Parallel.ForEach循环?)我仍然不确定在效率和并行设计方面适用的是什么.此示例将Parallel.Foreach处理应用于列表的语句,其中两个循环都在该列表上执行操作.
在我的例子中,循环正在做不同的事情,所以,我应该:
两个完成转换后,如何重新编写代码完成的代码?我认为完成意味着它被标记为完成并且"出队列"是空的?
public Test()
{
broadCastBlock = new BroadcastBlock<int>(i =>
{
return i;
});
transformBlock1 = new TransformBlock<int, string>(i =>
{
Console.WriteLine("1 input count: " + transformBlock1.InputCount);
Thread.Sleep(50);
return ("1_" + i);
});
transformBlock2 = new TransformBlock<int, string>(i =>
{
Console.WriteLine("2 input count: " + transformBlock1.InputCount);
Thread.Sleep(20);
return ("2_" + i);
});
processorBlock = new ActionBlock<string>(i =>
{
Console.WriteLine(i);
});
//Linking
broadCastBlock.LinkTo(transformBlock1, new DataflowLinkOptions { PropagateCompletion = true });
broadCastBlock.LinkTo(transformBlock2, new DataflowLinkOptions { PropagateCompletion = true });
transformBlock1.LinkTo(processorBlock, new DataflowLinkOptions { …Run Code Online (Sandbox Code Playgroud) 我正在写一个网页,它会调用一些Web服务.这些电话看起来像这样:
var Data1 = await WebService1.Call();
var Data2 = await WebService2.Call();
var Data3 = await WebService3.Call();
Run Code Online (Sandbox Code Playgroud)
在代码审查期间,有人说我应该将其更改为:
var Task1 = WebService1.Call();
var Task2 = WebService2.Call();
var Task3 = WebService3.Call();
var Data1 = await Task1;
var Data2 = await Task2;
var Data3 = await Task3;
Run Code Online (Sandbox Code Playgroud)
为什么?有什么不同?
我知道异步编程多年来已经发生了很多变化.我有点尴尬,我让自己在34岁时就生锈了,但我依靠StackOverflow让我加快速度.
我想要做的是在一个单独的线程上管理一个"工作"队列,但是这样一次只能处理一个项目.我想在这个线程上发布工作,它不需要将任何内容传递给调用者.当然,我可以简单地旋转一个新Thread对象并让它在一个共享Queue对象上循环,使用睡眠,中断,等待句柄等.但是我知道事情从那以后变得更好.我们有BlockingCollection,Task,async/ await,更不用提的NuGet包,可能抽象了很多的.
我知道"什么是最好的..."这些问题通常是不受欢迎的,所以我会通过说"目前推荐的是什么......"的方式来改进它,最好使用内置的.NET机制来完成这样的事情.但是如果第三方NuGet包简化了一堆东西,它也是如此.
我认为一个TaskScheduler固定最大并发度为1 的实例,但似乎现在可能没那么笨重的方法了.
背景
具体来说,我在这种情况下尝试做的是在Web请求期间排队IP地理定位任务.相同的IP可能会多次排队等待地理定位,但是任务将知道如何检测并尽快跳过,如果它已经解决了.但请求处理程序只是将这些() => LocateAddress(context.Request.UserHostAddress)调用抛入队列,让该LocateAddress方法处理重复的工作检测.我正在使用的地理位置API不喜欢被请求轰炸,这就是我想一次将它限制为单个并发任务的原因.但是,如果允许通过简单的参数更改轻松扩展到更多并发任务,那将是很好的.
为什么parallel.ForEach循环使用OperationCancelledException退出,同时使用GetConsumableEnumerable?
//outside the function
static BlockingCollection<double> _collection = new BlockingCollection<double>();
var t = Task.Factory.StartNew(Producer);
Parallel.ForEach(_collection.GetConsumingEnumerable(),item => Console.WriteLine("Processed {0}", item));
Console.WriteLine("FINISHED processing");
public static void Producer()
{
var data = Enumerable.Range(1, 1000);
foreach (var i in data)
{
_collection.Add(i);
Console.WriteLine("Added {0}",i);
}
Console.WriteLine("Finished adding");
_collection.CompleteAdding();
}
Run Code Online (Sandbox Code Playgroud) 我有一个按钮,可以产生4个任务.相同的按钮更改为取消按钮,单击此按钮将取消所有4个任务.我是否应该将相同的取消令牌传递给所有4个任务并让他们对IsCancelRequested的相同令牌进行轮询?在createlinkedtokensource上阅读msdn doc后我很困惑.这通常是怎么做的?谢谢
更新:Task.WaitAll()等待所有任务完成执行.类似地,一旦共享取消令牌源设置为取消,如何知道何时取消所有任务.
如果使用LongRunning选项创建任务,则会产生任何副作用,因为它们不使用ThreadPool
我正在构建一个必须处理大量数据的控制台应用程序.
基本上,应用程序从数据库中获取引用.对于每个引用,解析文件的内容并进行一些更改.这些文件是HTML文件,并且该过程正在使用RegEx替换进行繁重的工作(查找引用并将它们转换为链接).然后将结果存储在文件系统中并发送到外部系统.
如果我按顺序恢复该过程:
var refs = GetReferencesFromDB(); // ~5000 Datarow returned
foreach(var ref in refs)
{
var filePath = GetFilePath(ref); // This method looks up in a previously loaded file list
var html = File.ReadAllText(filePath); // Read html locally, or from a network drive
var convertedHtml = ParseHtml(html);
File.WriteAllText(destinationFilePath); // Copy the result locally, or a network drive
SendToWs(ref, convertedHtml);
}
Run Code Online (Sandbox Code Playgroud)
我的程序工作正常,但速度很慢.这就是为什么我想要并行化这个过程.
到现在为止,我做了一个简单的并行化添加AsParallel:
var refs = GetReferencesFromDB().AsParallel();
refs.ForAll(ref=>
{
var filePath = GetFilePath(ref);
var html = File.ReadAllText(filePath);
var convertedHtml = …Run Code Online (Sandbox Code Playgroud) c# parallel-processing multithreading plinq task-parallel-library
我在C#中使用Tasks非常如此,但是当我尝试从方法中返回一个Task时,我感到很困惑,而且该方法本身会执行多个任务.那么我是否让我的方法启动一个新的任务,然后在那里顺序完成所有事情?用.ContinueWith()来完成这一切是很难的.
例:
public Task<string> GetSomeData(CancellationToken token)
{
return Task.Factory.StartNew(() =>
{
token.ThrowIfCancellationRequested();
var initialData = GetSomeInteger(token).Result;
return GetSomeString(initialData, token).Result;
});
}
public Task<int> GetSomeInteger(CancellationToken token)
{
return Task<int>.Factory.StartNew(() =>
{
return 4;
}, token);
}
public Task<string> GetSomeString(int value, CancellationToken token)
{
return Task<string>.Factory.StartNew(() =>
{
return value.ToString();
}, token);
}
Run Code Online (Sandbox Code Playgroud)
我不确定如何编写此方法以使其正确使用任务.我想我觉得应该有一个.ContinueWith在那里或什么的.
可能的修复?
public Task<string> GetSomeData(CancellationToken token)
{
return GetSomeInteger(token).ContinueWith((prevTask) =>
{
return GetSomeString(prevTask.Result, token);
}, token).Unwrap();
}
Run Code Online (Sandbox Code Playgroud) Sometimes, once I have requested the cancellation of a pending task with CancellationTokenSource.Cancel, I need to make sure the task has properly reached the cancelled state, before I can continue. Most often I face this situation when the app is terminating and I want to cancel all pending task gracefully. However, it can also be a requirement of the UI workflow specification, when the new background process can only start if the current pending one has been fully …
c# ×9
.net ×4
concurrency ×3
async-await ×2
c#-4.0 ×2
.net-4.0 ×1
.net-4.5 ×1
asynchronous ×1
performance ×1
pfx ×1
plinq ×1
task ×1
tpl-dataflow ×1
web-services ×1