Mar*_*ser 3 c# multithreading task multitasking task-parallel-library
var finalList = new List<string>();
var list = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ................. 999999};
var init = 0;
var limitPerThread = 5;
var countDownEvent = new CountdownEvent(list.Count);
for (var i = 0; i < list.Count; i++)
{
var listToFilter = list.Skip(init).Take(limitPerThread).ToList();
new Thread(delegate()
{
Foo(listToFilter);
countDownEvent.Signal();
}).Start();
init += limitPerThread;
}
//wait all to finish
countDownEvent.Wait();
private static void Foo(List<int> listToFilter)
{
var listDone = Boo(listToFilter);
lock (Object)
{
finalList.AddRange(listDone);
}
}
Run Code Online (Sandbox Code Playgroud)
这不是:
var taskList = new List<Task>();
for (var i = 0; i < list.Count; i++)
{
var listToFilter = list.Skip(init).Take(limitPerThread).ToList();
var task = Task.Factory.StartNew(() => Foo(listToFilter));
taskList.add(task);
init += limitPerThread;
}
//wait all to finish
Task.WaitAll(taskList.ToArray());
Run Code Online (Sandbox Code Playgroud)
此过程最终必须至少创建700个线程.当我使用Thread运行时,它可以工作并创建所有这些.但Task它没有..似乎它没有启动倍数Tasks异步.
我真的想知道为什么......任何想法?
编辑
PLINQ的另一个版本(如建议的那样).
var taskList = new List<Task>(list.Count);
Parallel.ForEach(taskList, t =>
{
var listToFilter = list.Skip(init).Take(limitPerThread).ToList();
Foo(listToFilter);
init += limitPerThread;
t.Start();
});
Task.WaitAll(taskList.ToArray());
Run Code Online (Sandbox Code Playgroud)
EDIT2:
public static List<Communication> Foo(List<Dispositive> listToPing)
{
var listResult = new List<Communication>();
foreach (var item in listToPing)
{
var listIps = item.listIps;
var communication = new Communication
{
IdDispositive = item.Id
};
try
{
for (var i = 0; i < listIps.Count(); i++)
{
var oPing = new Ping().Send(listIps.ElementAt(i).IpAddress, 10000);
if (oPing != null)
{
if (oPing.Status.Equals(IPStatus.TimedOut) && listIps.Count() > i+1)
continue;
if (oPing.Status.Equals(IPStatus.TimedOut))
{
communication.Result = "NOK";
break;
}
communication.Result = oPing.Status.Equals(IPStatus.Success) ? "OK" : "NOK";
break;
}
if (listIps.Count() > i+1)
continue;
communication.Result = "NOK";
break;
}
}
catch
{
communication.Result = "NOK";
}
finally
{
listResult.Add(communication);
}
}
return listResult;
}
Run Code Online (Sandbox Code Playgroud)
Tasks不是多线程的.它们可以用于它,但大多数它们实际上用于相反的 - 在一个线程上多路复用.
要使用任务进行多线程处理,我建议使用Parallel LINQ.它已经有很多优化,例如列表的智能分区,只产生与CPU核心一样多的线程等.
要理解Task并async以这种方式考虑它 - 典型的工作负载通常包括需要等待的IO.也许您阅读文件,查询Web服务,或访问数据库等等.关键是 - 你的线程会等待一段时间(至少在CPU周期内),直到你从一些遥远的目的地得到一个响应.
在Olden Days™中,这意味着您的线程被锁定(暂停),直到响应出现.如果你想在此期间做其他事情,你需要生成一个新线程.这是可行的,但效率不高.每个OS线程都带有很大的开销(内存,内核资源).并且你可能最终会有几个线程主动烧毁CPU,这意味着操作系统需要在它们之间切换,这样每个都会获得一点CPU时间,而这些"上下文切换"非常昂贵.
async改变工作流程.现在,您可以在同一个线程上执行多个工作负载.虽然一项工作是await来自遥远的来源的结果,但另一项工作可以介入并使用该线程来做其他有用的事情.当第二个工作负载达到自己的状态时await,第一个工作负载可以唤醒并继续.
毕竟,产生比CPU内核更多的线程是没有意义的.你不会以这种方式完成更多的工作.恰恰相反 - 更多时间将用于切换线程,并且可用于有用工作的时间更少.
这就是Task/ async/ await最初设计的目的.然而,并行LINQ也利用它并将其重用于多线程.在这种情况下,您可以这样看待 - 其他线程是您的主线程是您的主线程正在等待的"遥远的目的地".
任务在线程池上执行.这意味着少数线程将服务于大量任务.您有多线程,但不是每个生成的任务的线程.
你应该使用任务.您的目标应该是使用与CPU一样多的线程.通常,线程池正在为您执行此操作.