C#使用代理发起并发请求时出现Empty Queue异常问题求助
问题根本原因
你代码的核心问题是LINQ查询的延迟执行特性导致的:
你定义
handlers时用的是Enumerable.Range(0, max).Select(...),返回的是未实际实例化的IEnumerable<ClearanceHandler>,属于延迟计算对象。每次你遍历/访问这个handlers的元素(比如gethandlerindexed里调用ElementAt)时,都会重新执行一遍Select里的逻辑,也就是会反复调用proxies.Dequeue()和useragents.Dequeue()。
第一次遍历的时候队列里的2个元素就被取出耗尽了,第二次再访问handlers元素时,队列已经为空,自然抛出空队列异常。
修复方案
- 立即实例化
handlers集合,避免延迟执行
只需要在定义handlers的Select语句末尾加.ToList(),提前把所有ClearanceHandler实例创建好存到列表里,后续访问不会再触发队列的出队操作:
var handlers = Enumerable.Range(0, max).Select(_ => new ClearanceHandler(proxies.Dequeue()) { UserAgent = useragents.Dequeue(), MaxTimeout = 6000 }).ToList();
- 修复共享变量
indext的线程安全问题indext是全局共享变量,多线程并发执行indext++是非原子操作,会出现计数错误,需要改用原子递增:
// 把 indext++; 替换为以下代码 int currentIndex = Interlocked.Increment(ref indext); var client = new HttpClient(gethandlerindexed(currentIndex, handlers));
额外优化建议
- 不要每次请求都新建
HttpClient实例,频繁创建销毁会导致套接字资源占用无法及时释放,建议每个ClearanceHandler对应一个复用的HttpClient实例 - 文件路径中的反斜杠需要转义,
PATH + "\proxy\proxy.txt"建议改为Path.Combine(PATH, @"proxy\proxy.txt")避免转义错误 - 全局变量
indext建议每次任务执行前重置为0,避免多次点击按钮后计数溢出错误
内容的提问来源于stack exchange,提问作者Theo Wanatin
相关产品推荐
相关产品推荐

