有没有办法多次执行一个方法,但要管理连接/线程?(.NET) 我有一个使用连接的方法(例如,下载页面的方法) 我必须多次执行此方法(例如下载1000页) 以同步和顺序的方式进行这项工作需要很长时间 我的资源有限(最多8个线程和/或最多50个并发连接) 我想利用一切资源来加速它 我知道并行化(PLINQ、并行扩展等)可以解决这个问题,但我已经尝试过了,这种方法由于资源匮乏而失败 我不想在管理资源的同时重新发明并行化这类任务的轮子,一定有人以前做过,并且为此提供了一个库/教程
有人能帮忙吗 更新当您开始混合异步调用和并行化以获得最大性能时,事情会变得更加复杂。这是在几个下载程序上实现的,比如Firefox downloader,它同时获得2次下载,当其中一次下载完成时,它将获得下一个文件,以此类推。也许它看起来很容易实现,但当我实现它时,我在使它通用化(对WebRequest和DbCommand有用)和处理问题(例如超时)方面遇到了困难,现在仍然有困难有没有办法多次执行一个方法,但要管理连接/线程?(.NET) 我有一个使用连接的方法(例如,下载页面的方法) 我必须多次执行此方法(例如下载1000页) 以同步和顺序的方式进行这项工作需要很长时间 我的资源有限(最多8个线程和/或最多50个并发连接) 我想利用一切资源来加速它 我知道并行化(PLINQ、并行扩展等)可以解决这个问题,但我已经尝试过了,这种方法由于资源匮乏而失败 我不想在管理资源的同时重新发明并行化这类任务的轮子,一定有人以前做过,并且为此提供了一个库/教程,.net,multithreading,connection,parallel-processing,.net,Multithreading,Connection,Parallel Processing,有人能帮忙吗 更新当您开始混合异步调用和并行化以获得最大性能时,事情会变得更加复杂。这是在几个下载程序上实现的,比如Firefox downloader,它同时获得2次下载,当其中一次下载完成时,它将获得下一个文件,以此类推。也许它看起来很容易实现,但当我实现它时,我在使它通用化(对WebRequest和DbCommand有用)和处理问题(例如超时)方面遇到了困难,现在仍然有困难 赏金猎人赏金将授予第一个链接可靠免费($$)的.NET库的人,该库提供了一种简单的C#方法,可以将异步任务并行化为H
赏金猎人赏金将授予第一个链接可靠免费($$)的.NET库的人,该库提供了一种简单的C#方法,可以将异步任务并行化为HttpWebRequests.BegingetResponse和SqlCommand.BeginExecutenQuery。并行化不能等待N个任务完成后再开始下一个N个任务,但必须在N个初始任务中的一个任务完成后立即启动一个新任务。该方法必须提供超时处理。您可以使用.NET类。您可以使用设置任何时候活动的最大线程数。查看连接的计数信号量。
编辑:要回答您的评论,.NET Framework已经有了一个 我强烈建议不要使用线程池,除非是很短的任务。如果您选择使用信号量,请确保您只阻塞正在排队工作项的代码,而不是在工作项代码的开头,否则如果您的(信号量最大计数*2)大于最大池线程数,您将快速死锁线程池 实际上,您永远无法安全地获取池线程上的锁,也无法安全地调用大多数异步API(或者像HttpWebRequest.GetResponse这样的同步API,因为它还可以在线程池上执行异步操作)
请参阅以获取一个好的示例。Jeffrey Richter有一个Power Threading库,它可能会对您有所帮助。它塞满了样品,非常强大。我找不到关于连接的快速示例,但是在协调多个异步操作方面,有很多示例可能适合您
它可以是,也有。另外,Jeffrey有一篇详细的文章解释了并发异步操作。您能提供更多信息说明为什么并行Linq不能工作吗 我的观点是,你的任务最适合PLinq。如果您在8核机器上运行,PLinq将拆分为8个任务,并为您将所有剩余任务排队 这是代码草案
PagesToDownload.AsParallel().ForAll(DownloadMethodWithLimitConnections);
我不明白为什么PLinq会消耗你的资源。根据我的测试,PLinq的性能甚至比使用ThreadPool更好。请参阅。这是一种“正确”的方法,尽管您可能会发现库的学习曲线有点太长了……异步WebRequest方法可能会显得很慢,因为它们在执行DNS查找时会阻塞,然后切换到异步行为。我自己也遵循了这条路径,将八个线程旋转以将请求提供给一个已经旋转线程来完成大部分工作的API似乎效率低下。您可能会重新考虑一些具有异步WebRequestAPI这一缺点的方法。我们的解决方案最终涉及到使用同步API,每个API都在自己的线程上。我对任何评论这种方法正确性的人都感兴趣。我不明白的是:你说最多50个连接,但只有8个线程。根据定义,每个连接都在一个线程中运行。我的意思是,您没有使用DMA或任何其他魔法来减轻CPU的负载,因此每次传输都需要一个执行上下文。如果您可以一次启动50个异步请求,很好,很好,可以这样做——您应该能够从同一个线程启动它们,因为调用异步读取函数基本上不需要任何时间。例如,如果您有8个内核,并且希望确保每个传输都有一个完整的内核(这可能是愚蠢的,但这是您的代码,所以…),那么您一次只能运行8个传输
我的建议是在一个同步块中启动50个异步请求,这样它们都会在您允许任何一个请求完成之前启动(简化了计算)。然后,使用Jeremy建议的计数信号量或mbeckish建议的同步队列来跟踪剩余的工作。在异步完成回调结束时,启动下一个连接(如果合适)。也就是说,启动50个连接,然后在其中一个连接完成后,使用“已完成”事件处理程序启动下一个连接,直到所有工作完成。这不需要任何类型的附加库或框架。这是使用.net 3.5中的基类库实现的方法: 对SetMinThreads的调用是可选的-查看使用和不使用它时会发生什么 你应该
public class ThrottledParallelRunnerTest
{
public static void Main()
{
//since the process is just starting up, we need to boost this
ThreadPool.SetMinThreads(10, 10);
IEnumerable<string> args = from i in Enumerable.Range(1, 100)
select "task #" + i;
ThrottledParallelRun(DoSomethingThatsSlow, args, 8);
}
public static void DoSomethingThatsSlow(string urlOrWhatever)
{
Console.Out.WriteLine("{1}: began {0}", urlOrWhatever, DateTime.Now.Ticks);
Thread.Sleep(500);
Console.Out.WriteLine("{1}: ended {0}", urlOrWhatever, DateTime.Now.Ticks);
}
private static void ThrottledParallelRun<T>(Action<T> action, IEnumerable<T> args, int maxThreads)
{
//this thing looks after the throttling
Semaphore semaphore = new Semaphore(maxThreads, maxThreads);
//wrap the action in a try/finally that releases the semaphore
Action<T> releasingAction = a =>
{
try
{
action(a);
}
finally
{
semaphore.Release();
}
};
//store all the IAsyncResult - will help prevent method from returning before completion
List<IAsyncResult> results = new List<IAsyncResult>();
foreach (T a in args)
{
semaphore.WaitOne();
results.Add(releasingAction.BeginInvoke(a, null, null));
}
//now let's make sure everything's returned. Maybe collate exceptions here?
foreach (IAsyncResult result in results)
{
releasingAction.EndInvoke(result);
}
}
}