python3-爬虫:11 进程线程 线程同步 线程池 线程安全 队列

进程与线程

在引入了线程的操作系统中,通常一个进程都有若干个线程,至少包含一个线程。

根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位

资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。
但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

点击查看进程与线程详细讲解

python中的线程模块

python 通过两个标准库thread和threading两个模块提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。

threading则拥有比较完善的线程方法:
	threading.currentThread()---返回当前的线程变量
	threading.enumerate()----返回正在运行的线程lis
	threading.activeCount----返回正在运行的线程数量
	
除此之外线程模块还提供了线程类,包含以下方法共开发者使用:
	run()----表示线程活动
	start()----启动线程活动
	join([time])----等待直到线程终止,
	isActive()----返回线程是否处于活动状态
	getName----返回线程名
	setName----设置线程名

进程同步

多线程的优势在于可以同时运行多个任务,节省时间,减少资源浪费。但是当线程需要共享数据时,可能存在数据不同步的情况

我们可以使用锁来保护数据,防止多个线程同时操作一组数据产生程序错误
Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于每次只允许一个线程操作的数据可将其放在这两个方法之间

还有一种方法是使用线程池,原理:将线程函数加入任务队列,每次从任务队列中抽取任务进行执行
点击查看线程池相关操作

线程安全 队列

queue,使用queue来保证线程安全,将线程加入的队列,从队列中取出线程进行实现

线程模块案例

import _thread
import time

class useThreadFun:
    """
    使用线程函数创建线程
    可以在线程函数中调用thread.exit()控制线程结束
    """
    def print_time(self, threadName, delay):
        count = 0
        while count < 5:
            time.sleep(delay)
            count += 1
            print("{}:{}".format(threadName, time.ctime(time.time())))

    def run(self):
        # 创建两个线程
        try:
            _thread.start_new_thread(self.print_time, ("Thread-1", 2))
            _thread.start_new_thread(self.print_time, ("Thread-2", 5))
        except:
            print("Error: unable to start thread")
        while 1:
            pass
if __name__ == "__main__":
	# 使用线程函数创建线程
    test1 = useThreadFun()
    test1.run()

使用Threading创建线程

import threading
import time

exitFlag = 0
class useThreading(threading.Thread): # 继承父类threading.Thread
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

    def run(self):
        """
        将要执行的代码放到run函数中,线程在创建后会直接运行run函数
        :return:
        """
        print('Starting:', self.name)
        print_time(self.name, self.counter, 5)
        print('exit:', self.name)


def print_time(threadName, counter, delay):
    while counter:
        if exitFlag:
            (threading.Thread).exit()
        time.sleep(delay)
        print('{}:{}'.format(threadName, time.ctime(time.time())))
        counter -= 1

if __name__ == "__main__":
	# 使用threaing创建线程
    thread1 = useThreading(1, 'thread_1', 1)
    thread2 = useThreading(2, 'thread_2', 2)

    # 开启线程
    thread1.start()
    thread2.start()

    print('exit main thread')

进程同步案例

import threading
import time

class threadSynchronization(threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

    def run(self):
        print("String:", self.name)

        threading.Lock().acquire()    # 获得锁
        print_time(self.name, self.counter, 3)
        threading.Lock().release()    # 释放锁

def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print('{}:{}'.format(threadName, time.ctime(time.time())))


if __name__ == "__main__":
    threads = []

    # 创建新线程
    thread1 = threadSynchronization(1, 'thread-1', 1)
    thread2 = threadSynchronization(2, 'thread-2', 2)

    # 开启新线程
    thread1.start()
    thread2.start()

    # 添加线程到线程列表
    threads.append(thread1)
    threads.append(thread2)

    # 等待所有线程完成
    for t in threads:
        t.join()

    print("exit main thread")


队列

import queue
import threading

# 简单的向队列中传输线程数
class  Threadingpool():
    def __init__(self, max_num=10):
        self.queue = queue.Queue(max_num)
        for i in range(max_num):
            self.queue.put(threading.Thread)

    def getthreading(self):
        return self.queue.get()

    def addthreading(self):
        self.queue.put(threading.Thread)

def func(p,i):
    time.sleep(1)
    print(i)
    p.addthreading()

if __name__ == '__main__':
    p = Threadingpool()
    for i in range(20):
        thread = p.getthreading()
        t = thread(target=func, args=(p, i))
        t.start()
import queue
import threading
import  contextlib
import time

# 向队列中无限添加任务 
# 此代码目前存在问题
StopEvent = object()
class ThreadPool(object):
    def __init__(self, max_num):
        self.q = queue.Queue()
        self.max_num = max_num
        self.terminal = False
        self.generate_list = []
        self.free_list = []

    def run(self, func, args, callback=None):
        """
        线程池执行一个任务
        :param func: 任务函数
        :param args: 任务函数所需的参数(return: 任务函数的执行状态和函数的返回值)
        :param callback: 回调函数
        :return: 线程池运行状态(True或False)
        """
        if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
            self.generate_thread()
        w = (func, args, callback)
        self.q.put(w)

    def generate_thread(self):
        """
        创建一个线程
        :return:
        """
        t = threading.Thread(target=self.call)
        t.start()

    def call(self):
        current_thread = threading.currentThread
        self.generate_list.append(current_thread)
        event = self.q.get()        # 获取线程
        while event != StopEvent:   # 判断线程是否为一个类
            func, arguments, callback = event
            try:
                result = func(*arguments)
                status = True
            except Exception as e:
                status = False
                result = e.args
            if callback is not None:
                try:
                    callback(status, result)
                except Exception as e:
                    pass
            with self.work_state():
                event = self.q.get()

        else:
            self.generate_list.remove(current_thread)

    def clase(self):
        """
        关闭线程, 给传输全局非元组的变量来进行关闭
        :return:
        """
        for i in range(len(self.generate_list)):
            self.q.put(StopEvent)

    def terminate(self):
        """
        突然关闭线程
        :return:
        """
        self.terminal = True
        while self.generate_list:
            self.q.put(StopEvent)
        self.q.empty()


    @contextlib.contextmanager
    def work_state(self):
        self.free_list.append(threading.currentThread)
        try:
            yield
        finally:
            self.free_list.remove(threading.current_thread)

def work(i):
    print(i)
    return i+1

def callback(ret):
    print(ret)

pool = ThreadPool(10)
for item in range(50):
    pool.run(func=work, args=(item), callback=callback)
pool.terminate()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值