C# 你如何利用任务衍生出大量的“任务”;火与遗忘”;工作
我有一个Windows应用程序,我想向它介绍一些功能。这个场景是,我有一个类,它有一个C# 你如何利用任务衍生出大量的“任务”;火与遗忘”;工作,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,我有一个Windows应用程序,我想向它介绍一些功能。这个场景是,我有一个类,它有一个Process方法,该方法将MailMessages的集合传递给它,以及当前的IMAP连接(使用AE.Net.Mail) 我想在另一个类中尽可能多地派生线程到Execute方法,该类接受单个MailMessage项,并将MailMessage发送到数据库,然后使用IMAP连接从服务器上删除MailMessage 我不太担心跟踪这些过程——我正在处理大量的电子邮件,也不担心我在向DB写信或删除邮件时会遇到一些错误
Process
方法,该方法将MailMessage
s的集合传递给它,以及当前的IMAP连接(使用AE.Net.Mail)
我想在另一个类中尽可能多地派生线程到Execute
方法,该类接受单个MailMessage
项,并将MailMessage
发送到数据库,然后使用IMAP连接从服务器上删除MailMessage
我不太担心跟踪这些过程——我正在处理大量的电子邮件,也不担心我在向DB写信或删除邮件时会遇到一些错误。我只需要应用程序尽快通过大量邮件
我一直在玩弄Task.Factory.StartNew
,但我真的不知道自己在做什么。我似乎无法启动它…以下是我尝试过的:
Task test = Task.Factory.StartNew(() =>
{
foreach (var mailMessage in _mms)
{
new ProcessMessage().Execute(mailMessage, imapConn);
}
});
我很确定在lamda表达式中不应该有循环,当我运行它时,它似乎没有进入
ProcessMessage.Execute
在lamdba表达式中绝对不应该有循环。试试这个:
_mms.ForEach(mms => {
Task.Factory.StartNew(() => ProcessMessage().Execute(mailMessage, imapConn))
});
如果您不担心跟踪结果或任何事情,则不需要保存任务的实例,例如Task test=。。。。您只需使用Task.Factory.StartNew()
在新线程中启动方法执行,这样我们就可以为您要处理的每封邮件启动一个新任务,并让线程池为我们处理事情
另外,
Task.Factory.StartNew
将用于在另一个返回邮件消息的线程中设置方法调用,因此,如果调用的是void方法,则无需执行此操作。Task
语法总是指使用新任务启动的方法的返回类型。它应该在单独的线程中执行每次执行(这样您就知道现在在做什么:)
或
现在,您正在将foreach循环作为一个单独的任务来执行,但您可能希望将每个迭代作为一个单独的任务来执行。您应该尝试Parallel.ForEach:
Parallel.ForEach(_mms, mailMessage =>
{
new ProcessMessage().Execute(mailMessage, imapConn);
});
这将并行执行迭代,这似乎是您正在尝试执行的操作。另一个选项是在集合上使用:
_mms.AsParallel()
.ForAll(mm => ProcessMessage().Execute(mm, imapConn));
当我运行它时,它似乎没有进入ProcessMessage.Execute
那么你的代码肯定还有其他问题,你的代码肯定能工作。如果您不想(或不能)并行化代码,在lambda中有一个循环可能是完全合适的
如果您确实想将其并行化(这在您的问题中不是很清楚),您可以使用例如
Parallel.ForEach()
,它正是为此而优化的。当您可以使用Task
s时,为什么建议使用ThreadPool
或Thread
?创建大量的线程是个坏主意。@svick你和像你这样的人能不能停止说这是个坏主意,并说出为什么这是个坏主意?如果有线程,为什么建议使用任务?你真的认为创建1000个任务比创建1000个排队线程好吗?当然,1000个Task
s比1000个Thread
s好得多(它们没有排队)。每个线程
消耗1 MB内存(和一些其他资源),而1000个任务
s将使用线程池
以更小的内存占用执行。因此,如果您在32位进程中运行,您的方法将极大地浪费资源,并且还很容易导致OutOfMemoryException
。使用ThreadPool
和创建新的线程之间存在巨大差异。我想说的是,您的第二个代码片段是对资源的严重浪费,因为它没有使用ThreadPool
。您的第一个代码片段要好得多,但是使用Task
s会更好,因为它有更好的API,并且还有一些性能改进。如果您直接使用ThreadPool
调用“创建排队线程”,那么我想您可能不知道线程是什么,因为这样说会产生很大的误导。但我承认我不知道“tcb”是什么意思,你能告诉我这一点吗?你的回答有些不准确Parallel.ForEach()
不会将每个迭代作为单独的任务执行,因为使用一个任务执行更多迭代的开销更小。如果“并行执行所有迭代”的意思是“一次执行所有迭代”,那么这也是错误的。@svick我不记得有人声称并行。Foreach()在单独的任务中执行每个迭代。。。更准确地说,我可能应该删除“all”一词。你写答案的方式意味着:“你可能希望将每个迭代作为一个单独的任务来执行。你应该尝试Parallel.ForEach[为此]”,它不会并行执行/all/iterations,它将按硬件和tpl库确定的批量执行它们。@JasonHiggins他提出了一种更易于阅读和更高效的方法(通过使用Parallel.ForEach()
)。他使用了一种方法(ForEach()
,而不是ForEach
),这种方法有时会遭到反对。所以,我不会说他是下一个Jon Skeet:-)OP有关于TPL的具体问题,这就是为什么我决定在回答中使用这种方法。此外,关于foreach vs foreach,我的理解是,在存在潜在不必要副作用的情况下,foreach扩展方法是不受欢迎的,我不认为使用TPL执行无效方法是使用此版本的坏情况。如果你对foreach更满意
Parallel.ForEach(_mms, mailMessage =>
{
new ProcessMessage().Execute(mailMessage, imapConn);
});
_mms.AsParallel()
.ForAll(mm => ProcessMessage().Execute(mm, imapConn));