C#爬虫总是只用一个 CPU 核心怎么排查? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
dfgxcvbcv
V2EX    程序员

C#爬虫总是只用一个 CPU 核心怎么排查?

  • &nbs;
  •   dfgxcvbcv 2022-05-31 19:10:33 +08:00 3204 次点击
    这是一个创建于 1229 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求是每秒查一次 MySQL ,发现有新任务就开始爬数据,速度要求每分钟 1~2 万个网页(内容有时效性,必须尽快爬完,每个网页的响应速度差别很大),解析出需要的数据后存入 MySQL 。(需要爬取的 URL 在程序运行时动态接收并添加到 MySQL 中,超时 /失败则按 MySQL 中的该域名的指定间隔(大部分是 1 秒,也有一些是 1 小时)重试,达到 MySQL 中的指定次数则在 MySQL 中标记失败不再重试)

    目前的做法是 async 异步请求(域名超时和重试次数限制用一个缓存模块自动缓存到 Redis ,失败任务如果设置的重试间隔小于一分钟则 Redis 存下次重试时间,否则存 MySQL ,MySQL 查询任务列表的时候用条件过滤没到时间的)+SemaphoreSlim 限制最大同时执行任务数量为 400 (因为有时候一分钟会添加十几万个网页,同时发这么多请求程序会卡死)。发现爬取速度比较慢,查了下 CPU 有一个核心占用 100%,剩下都不到 1%。带宽因为大部分是下行,阿里云共享不知道多大的下行带宽只用了 18Mbps ,独享 7Mbps 上行带宽只用了 2Mbps 。MySQL 用的是阿里云云数据库。Redis 在本机(指爬数据的服务器上)。

    被爬网站均没有限流。

    21 条回复    2022-06-01 15:14:35 +08:00
    Juszoe
        1
    Juszoe  
       2022-05-31 20:03:06 +08:00
    不懂 C#,但是 async 异步在大部分语言里都是单线程运行吧
    dfgxcvbcv
        2
    dfgxcvbcv  
    OP
       2022-05-31 20:04:54 +08:00
    @Juszoe #1 Google 了下好像确实是这样,那这种场景怎么设计最好呢?
    Juszoe
        3
    Juszoe  
       2022-05-31 20:16:06 +08:00
    @dfgxcvbcv #2 你的任务负载这么大,得上多线程才能利用更多的核心。将任务分解出来,每个线程内可以用 async ,一个线程带几万个协程还是太为难了
    ly841000
        4
    ly841000  
       2022-05-31 20:19:57 +08:00
    @dfgxcvbcv c# async 不是单线程
    Building
        5
    Building  
       2022-05-31 20:31:02 +08:00
    多线程应该和 thread 有关吧,async 只是把任务放到不同的 queue ,thread 不变,当然就只有一个核心的 CPU 在跑,不知道 C# 是不是这样
    ikesnowy
        6
    ikesnowy  
       2022-05-31 20:34:21 +08:00
    你在本地运行可以跑满多个 CPU 吗?排除服务器和部署的原因,如果本地也跑不满的话就是代码写得有问题了。
    thinkershare
        7
    thinkershare  
       2022-05-31 20:37:35 +08:00
    使用一个主线程去发送请求(和 MySQL 打交道, 发送异步请求), 关闭同步上下文, 然后在主线程上发送 HTTP 请求, 然后主线程就等待(用 Task.Delay()), 时间到了再次轮询数据库. 在 HTTP 的 IO 的 Task 上附加成功的后续操作, 这个操着会在线程池中获取一个空闲线程, 然后执行. 一开始配置好线程池的物理线程数量和 I/O 线程数量. 你给出来的信息太有限了, 很难给你分析. 另外真个场景我估计瓶颈不在 CPU, 如果后续操作费事很少, 则 CPU 应该一直空闲, 如果你开启了上下文同步, 则可能导致主线程假死!
    thinkershare
        8
    thinkershare  
       2022-05-31 20:38:41 +08:00
    @Building C#的 Task 比较复杂, 并不是简单的协程, 既可以多线程, 也可以单线程
    Soar360
        9
    Soar360  
       2022-05-31 20:43:12 +08:00
    如果是 framework 的话,看看是不是限制并发了?
    Buges
        10
    Buges  
       2022-05-31 20:43:43 +08:00 via Android
    你这种情况,盲猜是阻塞了。哪里有 CPU 密集型都任务,把线程给占了。
    纯异步 IO 话单线程 /多线程的 executor 没有太显著的差异。
    ragnaroks
        11
    ragnaroks  
       2022-05-31 20:44:00 +08:00
    不知道楼主什么水平,但是并不是 public async void function1() 就是异步,没有代码不好诊断,可以先把任务压倒一个 list ,用并行去跑,简单快捷
    netnr
        12
    netnr  
       2022-05-31 21:16:35 +08:00
    C# 并行任务 Parallel 类
    https://www.netnr.com/home/list/139
    ration
        13
    ration  
       2022-05-31 21:34:13 +08:00 via Android
    异步的话所有方法都得异步,排查下是不是有些方法写成同步阻塞了。
    darklights
        14
    darklights  
       2022-05-31 22:29:48 +08:00
    async 是异步,不是并行,如果代码这样写:
    while (link != null) {
    var cOntent= await Fetch(link);
    await Save(content);
    link = FindNext(html);
    }

    那跑起来跟 JS 一样,只能用一个核。
    SMGdcAt4kPPQ
        15
    SMGdcAt4kPPQ  
       2022-05-31 22:56:34 +08:00
    不发代码不好分析,可能就是和楼上说的一样立即 await
    forgottencoast
        16
    forgottencoast  
       2022-05-31 23:39:04 +08:00
    上面很多人说了,异步和并行是两个概念。
    默认情况下异步你用 await 的话,CPU 就是单线程的,但是 IO 方面可以并发。
    简单一点,你可以不要 await ,然后任务完成以后自己处理回调。
    要想优雅就用前面#12 提到的 Parallel 。
    一般情况下爬虫 CPU 不应该跑满的,除非你大量分析内容,带宽要先跑满,你还是要重新分析一下自己的代码。
    fanxiao
        17
    fanxiao  
       2022-06-01 08:31:51 +08:00
    直接将这个 task 丢到 ThreadPool 里面运行就好了 , 主线程 await io 资源还没有返回,不会往下面执行,本质跟你写个同步语句没有区别,只是当 io 资源满足之后方便回到现场,所以还需要 task.Run 或者 ThreadPool 来支持多线程.
    fanxiao
        18
    fanxiao  
       2022-06-01 08:33:19 +08:00
    ClorisYe
        19
    ClorisYe  
       2022-06-01 09:59:41 +08:00
    异步是开辟一个后台线程去做 IO 的,当你 await 的时候,主线程在等待异步线程的执行回调。所以,异步本身是多线程实现的,这个你可以通过在异步方法内打印线程 ID 可以看到与主线程的是不一样的。如果你想同时开多个异步 IO ,你可以把任务存放到一个队列里面,然后遍历 await 。这样批量任务可以同时执行。
    beginor
        20
    beginor  
       2022-06-01 12:45:31 +08:00 via Android
    #12 楼上正解,parallel 可以调用全部 CPU 核心
    billzhuang
        21
    billzhuang  
       2022-06-01 15:14:35 +08:00
    不管是查 mysql 还是爬虫,都是 io bound ,正确使用 async/await 一个核心都嫌多。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2718 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 20ms UTC 07:45 PVG 15:45 LAX 00:45 JFK 03:45
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86