多线程 - 为何python子线程会等待很长时间
高洛峰
高洛峰 2017-04-18 09:32:14
0
2
680

背景:运行一个爬虫,开了10个线程,每个线程先去爬取指定数量的代理作为自己的代理池,然后开始工作。

问题:下面是爬虫日志的两行,可以看到在第一行任务处等待了45秒,而这里不过是输出一条信息,十分不理解为什么等了这么长时间?日志中像这样动辄十几秒什么一两分钟的情形基本都发生在爬取代理的过程中,是否意味着这个任务的代码有问题?

15:57:50    INFO    Thread-2    the proxy already in list, skip
15:58:35    INFO    Thread-10       {'https': '117.170.28.178:8123'} download 2111 bytes in 0.75 seconds(average in 1 tries), need 10, available count: 7    

思考:我理解python的多线程调度机制是完成了一条指令后,就可以调用其他线程了,并不是一定要等着这个指令得到了预期的结果,那么如果我的代码写的有问题也不至于影响他的调度吧。这个线程没有进展又不将CPU的使用权让渡出来,GIL为什么不剥夺这个线程的运行时间,总不至于是在等待某个程序块或者函数运行完毕吧。

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

répondre à tous(2)
小葫芦

Il s'avère que le problème décrit est principalement dû à une utilisation inappropriée de SQLite. La conception précédente consistait à ouvrir une connexion jusqu'à ce que la vérification de tous les agents du pool d'agents soit terminée et qu'un certain nombre d'agents soient capturés avant de fermer la connexion. connexion, et à chaque fois Lors de l'ajout, de la modification ou de la suppression d'informations sur l'agent, des fichiers de données sont écrits, ce qui entraîne le verrouillage prolongé de SQLite à gros grains.

Après avoir découvert ce problème, nous l'avons optimisé. Après avoir lu l'agent d'inventaire au début de la nouvelle connexion, nous avons immédiatement fermé la connexion. Après cela, toutes les données nouvelles, mises à jour et supprimées de l'agent sont temporairement stockées dans des variables de classe jusqu'à ce que. tous les agents requis sont obtenus. Ensuite, ouvrez une nouvelle connexion, mettez à jour les données avec executemany, puis fermez la connexion, terminez la tâche planifiée et la vitesse augmentera.

Cependant, je n'arrive toujours pas à comprendre pourquoi dans la situation d'origine, le mécanisme de planification des threads permet au thread bloqué par la base de données d'occuper toujours des ressources au lieu de changer dans le temps ?

伊谢尔伦

Votre fil de discussion est donc bloqué au niveau de l'écriture dans la base de données. Puisque vous utilisez sqlite, laissez-moi vous donner un autre pouvoir ancien pour accélérer l'opération d'écriture dans la base de données :

import sqlite3

...
conn = sqlite3.connect('xxx.db')
cur = conn.cursor()
cur.execute("CREATE TABLE xxx")  # 建个表
cur.execute("PRAGMA synchronous = OFF")  # 关闭磁盘同步
cur.execute("BEGIN TRANSACTION")  # 开始事务处理
cur.executemany("INSERT INTO names VALUES (?,?)", lst)  # 批量插入爬到的数据
conn.commit()
conn.close()
...

Trois méthodes sont utilisées pour accélérer la sqlitevitesse d'écriture

  1. Désactiver la synchronisation des disques

  2. Transactions SQLite

  3. exécuter de nombreuses insertions par lots

PS : De plus, si vous disposez de suffisamment de mémoire, vous pouvez jeter le fichier de base de données dans le répertoire tmpfs, ce qui éliminera grandement l'impact des E/S disque (équivalent à une écriture directe en mémoire)

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal