Python使用多线程(附:爬虫使用的线程池)

python开启多线程。

使用的库:
    python 3.+ :threading(较高级,常用),   _thread(python2.+中叫 thread)(偏底层)
    python 2.+ :thread

实现多线程:(python3.6,使用 threading 库)
   1:函数实现

 #第一种:通过函数创建线程
 def 函数a():
     pass

# 获得一个线程对象。
 t = threading.Thread(target=函数a的名字,name=自己随便取的线程名字,args=(参数1,...))   

# 启动线程 
 t.start();


   2:继承线程类(类实现)

class Fetcher(threading.Thread):
        def __init__(self):
            Thread.__init__(self):

            #加这一步的目的是保证,主线程退出后子线程也会跟着中断退出
            self.daemon = True
    # 必须要写
        def run(self):
            #线程运行的函数
            pass

# 获得对象,并启动线程
t = Fetcher()
t.start()

锁:

线程同时操作一个全局变量时会产生线程竞争所以,需要锁来避免竞争。
实现锁:

 lock = threading.Lock()
 
 lock.acquire()      #获得锁,加锁

 #..操作全局变量..(写文件,写入数据库等)

 lock.release()      #释放锁

队列:(线程池中使用)

多线程同步就是多个线程竞争一个全局变量时按顺序读写,一般情况下要用锁,但是使用标准库里的Queue的时候它内部已经实现了锁,不用程序员自己写了。

使用队列(只介绍在线程池中的常用方法):

# 导入队列类:

from queue import Queue

# 创建一个队列:

q = Queue(maxsize=0)   # maxsize为队列大小,为0默认队列大小可无穷大。

# 队列是先进先出的数据结构:

q.put(item) #往队列添加一个item,队列满了则阻塞
q.get(item) #从队列得到一个item,队列为空则阻塞

还有相应的不等待的版本,这里略过。

队列不为空,或者为空但是取得item的线程没有告知任务完成时都是处于阻塞状态

q.join()    #阻塞直到所有任务完成

# 线程告知任务当前任务已结束,可以开始下次任务使用 task_done() 函数

q.task_done() #在线程内调用

==============================实现简单线程池(爬虫使用)==================================
1:创建一个线程类:

class TestThread(threading.Thread):
    def __init__(self,task,lock):
        threading.Thread.__init__(self);
        self.task = task ;  # 一个队列,用来存放要爬取的url
        self.lock = lock ; # 一个锁对象,用来保护存入数据库等的操作
        self.daemon = True; # 当主线程退出时,子线程也退出。
        self.start(); # 运行当前线程。
    
    # 线程中的主运行方法
    def run(self):
        while True:
            # 从队列中获取url,若没有则一直阻塞,直到获取到一个url。
            url = self.task.get(); 
            """
            这里进行爬数据的操作
            """
            # 向任务禀报当前任务执行结束,可以开始下一任务
            self.task.task_done();

2:创建一个线程池类

class ThreadPool():
    def __init__(self,thread_num,lock):
        self.task = queue.Queue(); # 生成一个队列,用来存储要爬取的连接
        self.lock = lock; # 一个锁对象,用来保护写入文件

    # 根据传入的线程数目,创建对应个线程
        for i in range(thread_num):
            TestThread(self.task,lock);

    def add_task(self,url):
        # 往队列中放url,直到队列满则阻塞。
        self.task.put(url)

    def wait_complite(self):
        # 阻塞队列中的所有线程,直到主线程执行完毕
        self.task.join();

 
3:使用

if __name__ == "__main__":
    print("开始于:",start)
        lock = threading.Lock();
        pool = ThreadPool(2,lock);
        for i in range(21):
            pool.add_task(i)
        pool.wait_complite();
        print("主线程结束");
        print("共用时:",time.time()-start)

猜你喜欢

转载自blog.csdn.net/hungpangzi/article/details/85334506
今日推荐