鱼C论坛

 找回密码
 立即注册
查看: 2434|回复: 3

[已解决]关于多线程堆列的问题

[复制链接]
发表于 2023-4-14 01:03:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
如图,初学者,想多线程写一个爬虫,构思了一个框架,尝试了一下,发现不能运行完整,中途就结束了,请各位大佬劳烦看一下问题在哪里。

代码如下

  1. import threading
  2. import time
  3. from queue import Queue
  4. import requests

  5. t1 = time.time()
  6. url_queue = Queue()


  7. def download():
  8.     while not url_queue.empty():
  9.         url=url_queue.get()
  10.         res = requests.get(url)
  11.         print(url,res.status_code,res.encoding)
  12.         return res.status_code
  13.     # print(res.headers)


  14. urls = ['http://www.038909.xyz', 'http://www.solucky.com.cn',
  15.         'http://www.baidu.com', 'http://www.bing.com', 'http://www.cnbeta.com', 'http://16666.com'

  16.         ]

  17. for url in urls:
  18.     url_queue.put(url)

  19. for i in range(3):
  20.     t = threading.Thread(target=download)
  21.     t.start()


复制代码


运行结果:
当range(3)时,只跑前三个,后面的url不跑。
/Volumes/DATA/PythonData/venv/bin/python /Volumes/DATA/doc&docx/2.py
http://www.038909.xyz 200 ISO-8859-1
http://www.baidu.com 200 ISO-8859-1
http://www.solucky.com.cn 502 None

最佳答案
2023-4-14 01:06:12
从你提供的代码来看,你创建了三个线程来执行 `download` 函数。每个线程在队列中取出一个 URL 进行下载,但是当 `download` 函数返回结果后,线程就结束了。所以你观察到的现象是只有前三个 URL 被处理了。

你可以通过让每个线程处理多个 URL 来解决这个问题。这可以通过在 `download` 函数中添加一个循环来实现。当一个线程处理完一个 URL 后,它将继续处理队列中的下一个 URL,直到队列为空。这里是修改后的代码:

  1. import threading
  2. import time
  3. from queue import Queue
  4. import requests

  5. t1 = time.time()
  6. url_queue = Queue()


  7. def download():
  8.     while not url_queue.empty():
  9.         url = url_queue.get()
  10.         res = requests.get(url)
  11.         print(url, res.status_code, res.encoding)
  12.         url_queue.task_done()  # 需要添加这行,以通知队列此任务已完成

  13. urls = [
  14.     'http://www.038909.xyz', 'http://www.solucky.com.cn',
  15.     'http://www.baidu.com', 'http://www.bing.com', 'http://www.cnbeta.com', 'http://16666.com'
  16. ]

  17. for url in urls:
  18.     url_queue.put(url)

  19. threads = []  # 创建一个线程列表,用于保存所有线程
  20. for i in range(3):
  21.     t = threading.Thread(target=download)
  22.     t.start()
  23.     threads.append(t)  # 把线程添加到线程列表

  24. # 等待所有任务完成
  25. url_queue.join()

  26. # 等待所有线程结束
  27. for t in threads:
  28.     t.join()

  29. t2 = time.time()
  30. print('Total time: ', t2 - t1)
复制代码


这样修改后,你的代码应该可以正确地处理所有的 URL 了。不过,还有一点需要注意:由于多线程操作不是线程安全的,可能会出现一些意外情况。在实际编写爬虫时,建议使用线程池 (如 `concurrent.futures.ThreadPoolExecutor`) 等更高级的并发工具,以确保程序的稳定性和可扩展性。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-4-14 01:06:12 | 显示全部楼层    本楼为最佳答案   
从你提供的代码来看,你创建了三个线程来执行 `download` 函数。每个线程在队列中取出一个 URL 进行下载,但是当 `download` 函数返回结果后,线程就结束了。所以你观察到的现象是只有前三个 URL 被处理了。

你可以通过让每个线程处理多个 URL 来解决这个问题。这可以通过在 `download` 函数中添加一个循环来实现。当一个线程处理完一个 URL 后,它将继续处理队列中的下一个 URL,直到队列为空。这里是修改后的代码:

  1. import threading
  2. import time
  3. from queue import Queue
  4. import requests

  5. t1 = time.time()
  6. url_queue = Queue()


  7. def download():
  8.     while not url_queue.empty():
  9.         url = url_queue.get()
  10.         res = requests.get(url)
  11.         print(url, res.status_code, res.encoding)
  12.         url_queue.task_done()  # 需要添加这行,以通知队列此任务已完成

  13. urls = [
  14.     'http://www.038909.xyz', 'http://www.solucky.com.cn',
  15.     'http://www.baidu.com', 'http://www.bing.com', 'http://www.cnbeta.com', 'http://16666.com'
  16. ]

  17. for url in urls:
  18.     url_queue.put(url)

  19. threads = []  # 创建一个线程列表,用于保存所有线程
  20. for i in range(3):
  21.     t = threading.Thread(target=download)
  22.     t.start()
  23.     threads.append(t)  # 把线程添加到线程列表

  24. # 等待所有任务完成
  25. url_queue.join()

  26. # 等待所有线程结束
  27. for t in threads:
  28.     t.join()

  29. t2 = time.time()
  30. print('Total time: ', t2 - t1)
复制代码


这样修改后,你的代码应该可以正确地处理所有的 URL 了。不过,还有一点需要注意:由于多线程操作不是线程安全的,可能会出现一些意外情况。在实际编写爬虫时,建议使用线程池 (如 `concurrent.futures.ThreadPoolExecutor`) 等更高级的并发工具,以确保程序的稳定性和可扩展性。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2023-4-14 01:12:52 | 显示全部楼层
isdkz 发表于 2023-4-14 01:06
从你提供的代码来看,你创建了三个线程来执行 `download` 函数。每个线程在队列中取出一个 URL 进行下载, ...

非常感谢,让我多了一点思考,和发现一些没想到的地方。再次感谢(那么晚还没睡)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-4-14 01:15:45 | 显示全部楼层
fineconey 发表于 2023-4-14 01:12
非常感谢,让我多了一点思考,和发现一些没想到的地方。再次感谢(那么晚还没睡)

不客气。最近熬夜熬习惯了,虽然知道熬夜不好
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-25 04:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表