📌 目录

    第4课-并发编程基础

    第4课:并发编程基础

    课程目标

    通过本课程学习,你将能够:

    • 理解进程与线程的区别和联系
    • 深入理解Python的GIL(全局解释器锁)机制
    • 熟练使用threading模块进行多线程编程
    • 掌握线程同步和锁的使用
    • 理解asyncio异步编程模型
    • 掌握协程的概念和使用
    • 为后续学习OneForAll的高性能并发处理打下基础

    4.1 进程与线程

    4.1.1 什么是进程?

    进程(Process)的定义:

    进程是程序在计算机上的一次执行活动,是系统进行资源分配和调度的基本单位。

    进程的特点:

    • 独立性:每个进程都有独立的内存空间
    • 资源拥有:每个进程拥有独立的资源(文件、内存等)
    • 并发性:多个进程可以并发执行
    • 动态性:进程是动态产生和消亡的

    进程的状态:

    """
    进程的三种基本状态:
    1. 就绪态(Ready):进程已获得除CPU外的所有资源,等待CPU调度
    2. 运行态(Running):进程正在CPU上执行
    3. 阻塞态(Blocked):进程因等待某个事件而暂停执行
    
    状态转换:
    就绪态 → 运行态:进程被CPU调度
    运行态 → 就绪态:时间片用完或被高优先级进程抢占
    运行态 → 阻塞态:等待I/O或其他事件
    阻塞态 → 就绪态:等待的事件发生
    """
    

    4.1.2 什么是线程?

    线程(Thread)的定义:

    线程是进程中的一个执行单元,是CPU调度的基本单位,也被称为轻量级进程。

    线程的特点:

    • 轻量级:线程的创建和销毁开销小
    • 共享资源:同一进程的线程共享内存和资源
    • 独立执行:每个线程有独立的执行流
    • 通信方便:线程间通信比进程间通信更简单

    线程与进程的关系:

    """
    进程 vs 线程:
    
    1. 包含关系
       进程包含线程,一个进程至少有一个线程(主线程)
       进程可以创建多个线程
    
    2. 资源共享
       进程:拥有独立的内存空间和资源
       线程:共享所属进程的内存和资源
    
    3. 开销对比
       进程:创建和销毁开销大,上下文切换开销大
       线程:创建和销毁开销小,上下文切换开销小
    
    4. 通信方式
       进程:需要使用IPC(进程间通信)机制
       线程:可以直接访问共享变量,通信更方便
    
    5. 安全性
       进程:相互隔离,一个进程崩溃不影响其他进程
       线程:一个线程崩溃可能导致整个进程崩溃
    """
    

    4.1.3 多进程 vs 多线程

    多进程的特点:

    """
    多进程的优点:
    1. 真正的并行执行(多核CPU)
    2. 进程间隔离,安全性高
    3. 可以充分利用多核CPU
    4. 一个进程崩溃不影响其他进程
    
    多进程的缺点:
    1. 创建和销毁开销大
    2. 进程间通信复杂
    3. 内存占用较大
    4. 上下文切换开销大
    
    适用场景:
    - CPU密集型任务
    - 需要真正并行的场景
    - 需要高隔离性的场景
    """
    

    多线程的特点:

    """
    多线程的优点:
    1. 创建和销毁开销小
    2. 线程间通信方便
    3. 内存占用小
    4. 上下文切换开销小
    
    多线程的缺点:
    1. 受GIL限制,无法利用多核CPU
    2. 需要处理线程安全问题
    3. 一个线程崩溃可能影响整个进程
    4. 调试相对复杂
    
    适用场景:
    - I/O密集型任务
    - 需要共享数据的场景
    - 需要快速响应的场景
    """
    

    4.1.4 Python中的多进程

    使用multiprocessing模块:

    import multiprocessing
    import time
    import os
    
    
    def worker(name, delay):
        """工作线程函数"""
        print(f"Worker {name} started (PID: {os.getpid()})")
        time.sleep(delay)
        print(f"Worker {name} finished (PID: {os.getpid()})")
    
    
    def multiprocessing_example():
        """多进程示例"""
        print(f"Main process PID: {os.getpid()}")
        
        # 创建进程
        process1 = multiprocessing.Process(target=worker, args=("A", 2))
        process2 = multiprocessing.Process(target=worker, args=("B", 3))
        
        # 启动进程
        process1.start()
        process2.start()
        
        # 等待进程结束
        process1.join()
        process2.join()
        
        print("All processes finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        multiprocessing_example()
    

    进程间通信:

    import multiprocessing
    
    
    def producer(queue):
        """生产者进程"""
        for i in range(5):
            queue.put(f"Item {i}")
        print("Producer finished")
    
    
    def consumer(queue):
        """消费者进程"""
        while True:
            item = queue.get()
            if item == "DONE":
                break
            print(f"Consumed: {item}")
        print("Consumer finished")
    
    
    def ipc_example():
        """进程间通信示例"""
        # 创建队列
        queue = multiprocessing.Queue()
        
        # 创建进程
        producer_process = multiprocessing.Process(target=producer, args=(queue,))
        consumer_process = multiprocessing.Process(target=consumer, args=(queue,))
        
        # 启动进程
        consumer_process.start()
        producer_process.start()
        
        # 等待生产者完成
        producer_process.join()
        
        # 发送结束信号
        queue.put("DONE")
        
        # 等待消费者完成
        consumer_process.join()
        
        print("IPC example finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        ipc_example()
    

    4.1.5 Python中的多线程

    使用threading模块:

    import threading
    import time
    import os
    
    
    def worker(name, delay):
        """工作线程函数"""
        print(f"Worker {name} started (Thread ID: {threading.current_thread().ident})")
        print(f"Worker {name} in process {os.getpid()}")
        time.sleep(delay)
        print(f"Worker {name} finished (Thread ID: {threading.current_thread().ident})")
    
    
    def threading_example():
        """多线程示例"""
        print(f"Main thread ID: {threading.current_thread().ident}")
        print(f"Main process PID: {os.getpid()}")
        
        # 创建线程
        thread1 = threading.Thread(target=worker, args=("A", 2))
        thread2 = threading.Thread(target=worker, args=("B", 3))
        
        # 启动线程
        thread1.start()
        thread2.start()
        
        # 等待线程结束
        thread1.join()
        thread2.join()
        
        print("All threads finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        threading_example()
    

    线程间共享数据:

    import threading
    import time
    
    
    class SharedCounter:
        """共享计数器"""
        
        def __init__(self):
            self.value = 0
        
        def increment(self):
            """增加计数"""
            self.value += 1
        
        def get_value(self):
            """获取当前值"""
            return self.value
    
    
    def worker(counter, name):
        """工作线程"""
        for _ in range(100000):
            counter.increment()
        print(f"Worker {name} finished")
    
    
    def shared_data_example():
        """线程间共享数据示例"""
        counter = SharedCounter()
        
        # 创建多个线程
        threads = []
        for i in range(5):
            thread = threading.Thread(target=worker, args=(counter, i))
            threads.append(thread)
            thread.start()
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print(f"Final counter value: {counter.get_value()}")
        # 注意:由于竞争条件,结果可能不是预期的500000
    
    
    # 使用示例
    if __name__ == "__main__":
        shared_data_example()
    

    4.2 GIL(全局解释器锁)机制

    4.2.1 什么是GIL?

    GIL的定义:

    GIL(Global Interpreter Lock,全局解释器锁)是Python解释器中的一种互斥锁,它确保在任何时候只有一个线程在执行Python字节码。

    GIL的作用:

    """
    GIL的目的:
    1. 保护Python对象的内部状态
    2. 简化内存管理
    3. 防止多线程同时访问Python对象导致的问题
    
    GIL的影响:
    1. 多线程无法在多核CPU上真正并行执行Python字节码
    2. 同一时刻只有一个线程在执行Python代码
    3. I/O密集型任务可以受益于多线程(I/O时会释放GIL)
    4. CPU密集型任务无法从多线程中获得性能提升
    """
    

    4.2.2 GIL的工作原理

    GIL的获取和释放:

    """
    GIL的获取和释放时机:
    
    获取GIL:
    1. 线程开始执行Python代码
    2. 从I/O操作返回
    3. 从等待中唤醒
    
    释放GIL:
    1. 执行I/O操作(如文件读写、网络请求)
    2. 执行时间片用完(默认约15ms)
    3. 执行需要长时间的操作(如某些C扩展函数)
    4. 显式释放(在C扩展中)
    
    注意:
    - GIL的释放和获取是自动的
    - Python代码无法直接控制GIL
    - 某些C扩展可以释放GIL以允许并行执行
    """
    

    4.2.3 GIL对多线程的影响

    演示GIL的影响:

    import threading
    import time
    
    
    def cpu_bound_task(n):
        """CPU密集型任务"""
        total = 0
        for i in range(n):
            total += i * i
        return total
    
    
    def io_bound_task():
        """I/O密集型任务"""
        time.sleep(1)
        return "Done"
    
    
    def test_cpu_bound():
        """测试CPU密集型任务"""
        print("=== CPU Bound Task ===")
        
        # 单线程
        start = time.time()
        cpu_bound_task(10000000)
        end = time.time()
        print(f"Single thread: {end - start:.2f}s")
        
        # 多线程(由于GIL,不会更快)
        start = time.time()
        threads = []
        for _ in range(2):
            thread = threading.Thread(target=cpu_bound_task, args=(5000000,))
            threads.append(thread)
            thread.start()
        
        for thread in threads:
            thread.join()
        
        end = time.time()
        print(f"Two threads: {end - start:.2f}s")
    
    
    def test_io_bound():
        """测试I/O密集型任务"""
        print("\n=== I/O Bound Task ===")
        
        # 单线程
        start = time.time()
        for _ in range(5):
            io_bound_task()
        end = time.time()
        print(f"Single thread: {end - start:.2f}s")
        
        # 多线程(由于I/O时释放GIL,会更快)
        start = time.time()
        threads = []
        for _ in range(5):
            thread = threading.Thread(target=io_bound_task)
            threads.append(thread)
            thread.start()
        
        for thread in threads:
            thread.join()
        
        end = time.time()
        print(f"Five threads: {end - start:.2f}s")
    
    
    # 使用示例
    if __name__ == "__main__":
        test_cpu_bound()
        test_io_bound()
    

    4.2.4 如何绕过GIL限制

    方法1:使用多进程

    import multiprocessing
    import time
    
    
    def cpu_intensive_task(n):
        """CPU密集型任务"""
        total = 0
        for i in range(n):
            total += i * i
        return total
    
    
    def use_multiprocessing():
        """使用多进程绕过GIL"""
        print("=== Using Multiprocessing ===")
        
        # 单进程
        start = time.time()
        cpu_intensive_task(10000000)
        end = time.time()
        print(f"Single process: {end - start:.2f}s")
        
        # 多进程(每个进程有自己的GIL,可以真正并行)
        start = time.time()
        processes = []
        for _ in range(2):
            process = multiprocessing.Process(
                target=cpu_intensive_task,
                args=(5000000,)
            )
            processes.append(process)
            process.start()
        
        for process in processes:
            process.join()
        
        end = time.time()
        print(f"Two processes: {end - start:.2f}s")
    
    
    # 使用示例
    if __name__ == "__main__":
        use_multiprocessing()
    

    方法2:使用C扩展

    """
    某些C扩展可以释放GIL,允许并行执行
    
    示例:
    - NumPy的数组操作
    - Pillow的图像处理
    - requests的网络请求(底层使用libcurl)
    
    这些库在执行耗时操作时会释放GIL
    """
    
    import numpy as np
    import threading
    import time
    
    
    def numpy_operation():
        """NumPy操作(会释放GIL)"""
        # 创建大数组
        arr = np.random.rand(10000000)
        # 执行计算(C代码,会释放GIL)
        result = np.sum(arr * arr)
        return result
    
    
    def test_numpy():
        """测试NumPy的多线程性能"""
        print("=== NumPy Multi-threading ===")
        
        # 单线程
        start = time.time()
        numpy_operation()
        end = time.time()
        print(f"Single thread: {end - start:.2f}s")
        
        # 多线程(NumPy会释放GIL,可以获得性能提升)
        start = time.time()
        threads = []
        for _ in range(4):
            thread = threading.Thread(target=numpy_operation)
            threads.append(thread)
            thread.start()
        
        for thread in threads:
            thread.join()
        
        end = time.time()
        print(f"Four threads: {end - start:.2f}s")
    
    
    # 使用示例
    if __name__ == "__main__":
        test_numpy()
    

    方法3:使用asyncio(异步编程)

    import asyncio
    import time
    
    
    async def async_task(name, delay):
        """异步任务"""
        print(f"Task {name} started")
        await asyncio.sleep(delay)  # 模拟I/O操作
        print(f"Task {name} finished")
        return f"Result {name}"
    
    
    async def async_main():
        """异步主函数"""
        print("=== Asyncio ===")
        
        start = time.time()
        
        # 并发执行多个异步任务
        results = await asyncio.gather(
            async_task("A", 1),
            async_task("B", 2),
            async_task("C", 1)
        )
        
        end = time.time()
        print(f"Total time: {end - start:.2f}s")
        print(f"Results: {results}")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(async_main())
    

    4.3 threading模块使用

    4.3.1 创建和启动线程

    方法1:使用函数创建线程

    import threading
    import time
    
    
    def simple_worker(name):
        """简单的工作线程"""
        print(f"Worker {name} started")
        time.sleep(2)
        print(f"Worker {name} finished")
    
    
    def create_thread_with_function():
        """使用函数创建线程"""
        # 创建线程
        thread = threading.Thread(target=simple_worker, args=("A",))
        
        # 启动线程
        thread.start()
        
        # 等待线程结束
        thread.join()
        
        print("Main thread finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        create_thread_with_function()
    

    方法2:使用类创建线程

    import threading
    import time
    
    
    class WorkerThread(threading.Thread):
        """工作线程类"""
        
        def __init__(self, name):
            super().__init__()
            self.name = name
        
        def run(self):
            """线程执行的方法"""
            print(f"Worker {self.name} started")
            time.sleep(2)
            print(f"Worker {self.name} finished")
    
    
    def create_thread_with_class():
        """使用类创建线程"""
        # 创建线程
        thread = WorkerThread("A")
        
        # 启动线程
        thread.start()			#不使用run(),因为不会创建新线程,只是在当前线程执行
        
        # 等待线程结束
        thread.join()
        
        print("Main thread finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        create_thread_with_class()
    

    方法3:使用线程池

    from concurrent.futures import ThreadPoolExecutor
    import time
    
    
    def worker(name, delay):
        """工作线程"""
        print(f"Worker {name} started")
        time.sleep(delay)
        print(f"Worker {name} finished")
        return f"Result {name}"
    
    
    def use_thread_pool():
        """使用线程池"""
        print("=== Thread Pool ===")
        
        # 创建线程池
        with ThreadPoolExecutor(max_workers=3) as executor:
            # 提交任务
            future1 = executor.submit(worker, "A", 1)
            future2 = executor.submit(worker, "B", 2)
            future3 = executor.submit(worker, "C", 1)
            
            # 获取结果
            result1 = future1.result()
            result2 = future2.result()
            result3 = future3.result()
            
            print(f"Results: {result1}, {result2}, {result3}")
        
        # 使用map批量提交任务
        with ThreadPoolExecutor(max_workers=3) as executor:
            results = executor.map(worker, ["D", "E", "F"], [1, 2, 1])
            for result in results:
                print(f"Map result: {result}")
    
    
    # 使用示例
    if __name__ == "__main__":
        use_thread_pool()
    

    4.3.2 线程属性和方法

    线程属性:

    import threading
    import time
    
    '''
    .name()				#线程名
    .ident()			#线程ID
    .is_alive()			#线程是否活跃
    .isDaemon()			#检查线程是否为守护线程
    .active_count()		#当前活动线程数
    .enumerate()		#获取当前所有活跃线程的列表
    '''
    
    def show_thread_info():
        """显示线程信息"""
        print(f"Current thread: {threading.current_thread().name}")
        print(f"Thread ID: {threading.current_thread().ident}")
        print(f"Is alive: {threading.current_thread().is_alive()}")
        print(f"Is daemon: {threading.current_thread().isDaemon()}")
    
    
    def worker(name):
        """工作线程"""
        show_thread_info()
        time.sleep(2)
        print(f"Worker {name} finished")
    
    
    def thread_properties():
        """线程属性示例"""
        print("=== Main Thread ===")
        show_thread_info()
        
        # 创建线程并设置属性
        thread = threading.Thread(
            target=worker,
            args=("A",),
            name="MyThread",
            daemon=False
        )
        
        print(f"\n=== Thread Before Start ===")
        print(f"Name: {thread.name}")
        print(f"Alive: {thread.is_alive()}")
        
        # 启动线程
        thread.start()
        
        print(f"\n=== Thread After Start ===")
        print(f"Alive: {thread.is_alive()}")
        
        # 等待线程结束
        thread.join()
        
        print(f"\n=== Thread After Join ===")
        print(f"Alive: {thread.is_alive()}")
        
        # 活跃线程数量
        print(f"\nActive threads: {threading.active_count()}")
        print(f"Thread list: {threading.enumerate()}")
    
    
    # 使用示例
    if __name__ == "__main__":
        thread_properties()
    

    守护线程:

    import threading
    import time
    
    
    def daemon_worker():
        """守护线程"""
        print("Daemon thread started")
        time.sleep(3)
        print("Daemon thread finished")
    
    
    def normal_worker():
        """普通线程"""
        print("Normal thread started")
        time.sleep(2)
        print("Normal thread finished")
    
    
    def daemon_example():
        """守护线程示例"""
        # 创建守护线程
        daemon_thread = threading.Thread(target=daemon_worker, daemon=True)
        
        # 创建普通线程
        normal_thread = threading.Thread(target=normal_worker, daemon=False)
        
        # 启动线程
        daemon_thread.start()
        normal_thread.start()
        
        # 只等待普通线程
        normal_thread.join()
        
        print("Main thread finished (daemon thread will be terminated)")
    
    
    # 使用示例
    if __name__ == "__main__":
        daemon_example()
    

    4.3.3 线程间通信

    使用队列(Queue)进行通信:

    import threading
    import queue
    import time
    
    
    def producer(q, items):
        """生产者线程"""
        print("Producer started")
        for item in items:
            q.put(item)
            print(f"Produced: {item}")
            time.sleep(0.5)
        print("Producer finished")
    
    
    def consumer(q):
        """消费者线程"""
        print("Consumer started")
        while True:
            try:
                item = q.get(timeout=2)
                print(f"Consumed: {item}")
                q.task_done()
            except queue.Empty:
                break
        print("Consumer finished")
    
    
    def queue_communication():
        """使用队列进行线程间通信"""
        # 创建队列
        q = queue.Queue()
        
        # 创建线程
        items = ["A", "B", "C", "D", "E"]
        producer_thread = threading.Thread(target=producer, args=(q, items))
        consumer_thread = threading.Thread(target=consumer, args=(q,))
        
        # 启动线程
        consumer_thread.start()
        producer_thread.start()
        
        # 等待线程结束
        producer_thread.join()
        consumer_thread.join()
        
        print("Queue communication finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        queue_communication()
    

    使用Event进行通信:

    import threading
    import time
    
    
    def worker(event, name):
        """工作线程"""
        print(f"Worker {name} waiting for event")
        event.wait()  # 等待事件被设置
        print(f"Worker {name} received event")
        time.sleep(1)
        print(f"Worker {name} finished")
    
    
    def event_communication():
        """使用Event进行线程间通信"""
        # 创建事件
        event = threading.Event()
        
        # 创建线程
        threads = []
        for i in range(3):
            thread = threading.Thread(target=worker, args=(event, i))
            threads.append(thread)
            thread.start()
        
        time.sleep(2)
        print("Setting event")
        event.set()  # 设置事件,唤醒所有等待的线程
        
        # 等待所有线程结束
        for thread in threads:
            thread.join()
        
        print("Event communication finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        event_communication()
    

    使用Condition进行通信:

    import threading
    import time
    import random
    
    
    class ProducerConsumer:
        """生产者消费者模型"""
        
        def __init__(self):
            self.items = []
            self.condition = threading.Condition()
        
        def produce(self, item):
            """生产物品"""
            with self.condition:
                self.items.append(item)
                print(f"Produced: {item}")
                self.condition.notify()  # 通知消费者
        
        def consume(self):
            """消费物品"""
            with self.condition:
                while not self.items:
                    print("Consumer waiting...")
                    self.condition.wait()  # 等待生产者通知
                item = self.items.pop(0)
                print(f"Consumed: {item}")
                return item
    
    
    def producer(pc):
        """生产者线程"""
        for i in range(5):
            item = f"Item-{i}"
            pc.produce(item)
            time.sleep(random.random())
    
    
    def consumer(pc):
        """消费者线程"""
        for _ in range(5):
            pc.consume()
            time.sleep(random.random())
    
    
    def condition_communication():
        """使用Condition进行线程间通信"""
        pc = ProducerConsumer()
        
        # 创建线程
        producer_thread = threading.Thread(target=producer, args=(pc,))
        consumer_thread = threading.Thread(target=consumer, args=(pc,))
        
        # 启动线程
        consumer_thread.start()
        producer_thread.start()
        
        # 等待线程结束
        producer_thread.join()
        consumer_thread.join()
        
        print("Condition communication finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        condition_communication()
    

    4.4 线程同步与锁

    4.1.1 为什么需要线程同步?

    线程安全问题:

    import threading
    
    
    class Counter:
        """计数器类(不安全)"""
        
        def __init__(self):
            self.value = 0
        
        def increment(self):
            """增加计数(不安全)"""
            # 这不是原子操作,可能导致竞争条件
            temp = self.value
            temp += 1
            self.value = temp
        
        def get_value(self):
            """获取当前值"""
            return self.value
    
    
    def unsafe_increment(counter):
        """不安全的增加计数"""
        for _ in range(100000):
            counter.increment()
    
    
    def race_condition_demo():
        """演示竞争条件"""
        counter = Counter()
        
        # 创建多个线程
        threads = []
        for _ in range(5):
            thread = threading.Thread(target=unsafe_increment, args=(counter,))
            threads.append(thread)
            thread.start()
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print(f"Expected: 500000")
        print(f"Actual: {counter.get_value()}")
        # 由于竞争条件,实际值通常小于预期值
    
    
    # 使用示例
    if __name__ == "__main__":
        race_condition_demo()
    

    4.4.2 使用Lock(锁)

    基本锁的使用:

    import threading
    
    
    class SafeCounter:
        """线程安全的计数器"""
        
        def __init__(self):
            self.value = 0
            self.lock = threading.Lock()  # 创建锁
        
        def increment(self):
            """线程安全的增加计数"""
            with self.lock:  # 使用上下文管理器自动获取和释放锁
                temp = self.value
                temp += 1
                self.value = temp
        
        def get_value(self):
            """获取当前值"""
            with self.lock:
                return self.value
    
    
    def safe_increment(counter):
        """线程安全的增加计数"""
        for _ in range(100000):
            counter.increment()
    
    
    def lock_demo():
        """使用Lock解决竞争条件"""
        counter = SafeCounter()
        
        # 创建多个线程
        threads = []
        for _ in range(5):
            thread = threading.Thread(target=safe_increment, args=(counter,))
            threads.append(thread)
            thread.start()
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print(f"Expected: 500000")
        print(f"Actual: {counter.get_value()}")
        # 使用锁后,结果应该是正确的
    
    
    # 使用示例
    if __name__ == "__main__":
        lock_demo()
    

    Lock的手动使用:

    import threading
    import time
    
    
    def manual_lock_demo():
        """手动使用Lock"""
        lock = threading.Lock()
        
        def worker(name):
            print(f"Worker {name} trying to acquire lock")
            lock.acquire()  # 获取锁
            try:
                print(f"Worker {name} acquired lock")
                time.sleep(1)
                print(f"Worker {name} releasing lock")
            finally:
                lock.release()  # 释放锁
        
        # 创建线程
        threads = []
        for i in range(3):
            thread = threading.Thread(target=worker, args=(i,))
            threads.append(thread)
            thread.start()
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print("Manual lock demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        manual_lock_demo()
    

    Lock的超时获取:

    import threading
    import time
    
    
    def lock_timeout_demo():
        """Lock超时获取示例"""
        lock = threading.Lock()
        
        def worker(name, timeout):
            print(f"Worker {name} trying to acquire lock")
            try:
                acquired = lock.acquire(timeout=timeout)  # 尝试获取锁,带超时
                if acquired:
                    print(f"Worker {name} acquired lock")
                    time.sleep(2)
                    print(f"Worker {name} releasing lock")
                    lock.release()
                else:
                    print(f"Worker {name} failed to acquire lock (timeout)")
            except Exception as e:
                print(f"Worker {name} error: {e}")
        
        # 创建线程
        thread1 = threading.Thread(target=worker, args=("A", -1))  # 无限等待
        thread2 = threading.Thread(target=worker, args=("B", 1))    # 1秒超时
        thread3 = threading.Thread(target=worker, args=("C", 1))    # 1秒超时
        
        thread1.start()
        time.sleep(0.5)  # 确保thread1先获取锁
        thread2.start()
        thread3.start()
        
        # 等待所有线程完成
        thread1.join()
        thread2.join()
        thread3.join()
        
        print("Lock timeout demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        lock_timeout_demo()
    

    4.4.3 使用RLock(可重入锁)

    什么是RLock?

    """
    RLock(Reentrant Lock,可重入锁):
    - 同一个线程可以多次获取同一个锁
    - 避免死锁
    - 需要同样次数的释放
    
    适用场景:
    - 递归函数
    - 同一个线程需要多次获取锁的情况
    """
    

    RLock的使用:

    import threading
    
    
    class RecursiveCounter:
        """使用RLock的递归计数器"""
        
        def __init__(self):
            self.value = 0
            self.lock = threading.RLock()  # 使用RLock
        
        def increment(self):
            """增加计数"""
            with self.lock:
                self.value += 1
                # 可以递归调用,因为RLock是可重入的
                if self.value < 100:
                    self.increment()
        
        def get_value(self):
            """获取当前值"""
            with self.lock:
                return self.value
    
    
    def rlock_demo():
        """RLock示例"""
        counter = RecursiveCounter()
        
        # 重置计数器
        counter.value = 0
        
        # 递归增加
        counter.increment()
        
        print(f"Final value: {counter.get_value()}")
        print("RLock demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        rlock_demo()
    

    RLock vs Lock对比:

    import threading
    
    
    def lock_reentrancy_demo():
        """Lock的可重入性对比"""
        
        # Lock不可重入
        def use_lock():
            lock = threading.Lock()
            
            def inner_function():
                with lock:  # 这会死锁,因为同一个线程不能重复获取Lock
                    print("Inner function acquired lock")
            
            with lock:
                print("Outer function acquired lock")
                try:
                    inner_function()
                except Exception as e:
                    print(f"Error with Lock: {e}")
        
        # RLock可重入
        def use_rlock():
            rlock = threading.RLock()
            
            def inner_function():
                with rlock:  # 这可以工作,因为RLock是可重入的
                    print("Inner function acquired lock")
            
            with rlock:
                print("Outer function acquired lock")
                inner_function()
                print("Outer function releasing lock")
        
        print("=== Lock (Not Reentrant) ===")
        use_lock()
        
        print("\n=== RLock (Reentrant) ===")
        use_rlock()
        
        print("Reentrancy demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        lock_reentrancy_demo()
    

    4.4.4 使用Semaphore(信号量)

    什么是Semaphore?

    """
    Semaphore(信号量):
    - 控制同时访问资源的线程数量
    - 内部维护一个计数器
    - acquire():计数器减1,如果为0则等待
    - release():计数器加1,唤醒等待的线程
    
    适用场景:
    - 限制并发连接数
    - 控制资源访问数量
    - 实现生产者消费者模型
    """
    

    Semaphore的使用:

    import threading
    import time
    
    
    def worker(semaphore, name):
        """工作线程"""
        print(f"Worker {name} trying to acquire semaphore")
        with semaphore:
            print(f"Worker {name} acquired semaphore")
            time.sleep(2)
            print(f"Worker {name} releasing semaphore")
        print(f"Worker {name} finished")
    
    
    def semaphore_demo():
        """Semaphore示例"""
        # 创建信号量,最多允许2个线程同时访问
        semaphore = threading.Semaphore(2)
        
        # 创建多个线程
        threads = []
        for i in range(5):
            thread = threading.Thread(target=worker, args=(semaphore, i))
            threads.append(thread)
            thread.start()
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print("Semaphore demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        semaphore_demo()
    

    限制并发连接数:

    import threading
    import time
    import random
    
    
    class ConnectionPool:
        """连接池(使用Semaphore限制连接数)"""
        
        def __init__(self, max_connections):
            self.max_connections = max_connections
            self.semaphore = threading.Semaphore(max_connections)
            self.active_connections = 0
        
        def acquire_connection(self, name):
            """获取连接"""
            print(f"{name} waiting for connection...")
            self.semaphore.acquire()
            self.active_connections += 1
            print(f"{name} acquired connection (active: {self.active_connections})")
        
        def release_connection(self, name):
            """释放连接"""
            self.active_connections -= 1
            print(f"{name} released connection (active: {self.active_connections})")
            self.semaphore.release()
        
        def use_connection(self, name, duration):
            """使用连接"""
            self.acquire_connection(name)
            try:
                time.sleep(duration)
                print(f"{name} finished using connection")
            finally:
                self.release_connection(name)
    
    
    def connection_pool_demo():
        """连接池示例"""
        pool = ConnectionPool(max_connections=3)
        
        # 创建多个线程
        threads = []
        for i in range(10):
            duration = random.uniform(1, 3)
            thread = threading.Thread(
                target=pool.use_connection,
                args=(f"Worker-{i}", duration)
            )
            threads.append(thread)
            thread.start()
            time.sleep(0.5)  # 错开线程启动时间
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        print("Connection pool demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        connection_pool_demo()
    

    4.4.5 使用BoundedSemaphore(有界信号量)

    什么是BoundedSemaphore?

    """
    BoundedSemaphore(有界信号量):
    - 与Semaphore类似,但会检查释放次数
    - 如果释放次数超过初始值,会抛出ValueError
    - 防止因编程错误导致的计数器溢出
    
    适用场景:
    - 需要确保信号量正确释放的情况
    - 调试和发现潜在问题
    """
    

    BoundedSemaphore的使用:

    import threading
    
    
    def bounded_semaphore_demo():
        """BoundedSemaphore示例"""
        # 创建有界信号量
        semaphore = threading.BoundedSemaphore(2)
        
        # 正确使用
        with semaphore:						#上下文管理器自动释放
            print("First acquire")
            with semaphore:
                print("Second acquire")
        
        # 错误使用(会抛出异常)
        try:
            semaphore.release()
            semaphore.release()  # 第二次release会抛出ValueError
            print("Extra release succeeded")
        except ValueError as e:
            print(f"Error: {e}")
        
        print("BoundedSemaphore demo finished")
    
    
    # 使用示例
    if __name__ == "__main__":
        bounded_semaphore_demo()
    

    4.5 asyncio异步编程基础

    4.5.1 什么是asyncio?

    asyncio的定义:

    asyncio是Python 3.4引入的异步I/O库,用于编写并发代码,使用async/await语法。

    asyncio的特点:

    """
    asyncio的特点:
    1. 单线程并发:在单个线程中实现并发
    2. 事件循环:核心是事件循环机制
    3. 协程:使用async/await定义协程
    4. 非阻塞I/O:I/O操作不会阻塞事件循环
    5. 高效:适合I/O密集型任务
    
    优势:
    1. 避免线程切换开销
    2. 没有线程安全问题
    3. 可以处理大量并发连接
    4. 代码更简洁易读
    
    适用场景:
    1. 网络请求
    2. 数据库操作
    3. 文件I/O
    4. WebSocket通信
    """
    

    4.5.2 协程(Coroutine)

    什么是协程?

    """
    协程(Coroutine):
    - 用户态的轻量级线程
    - 由程序自己控制调度
    - 可以暂停和恢复执行
    - 比线程更轻量级
    
    协程 vs 线程:
    1. 协程由用户调度,线程由操作系统调度
    2. 协程切换开销小,线程切换开销大
    3. 协程没有线程安全问题
    4. 协程适合I/O密集型任务
    """
    

    定义和使用协程:

    import asyncio
    import time
    
    
    async def simple_coroutine(name, delay):
        """简单的协程"""
        print(f"Coroutine {name} started")
        await asyncio.sleep(delay)  # 模拟I/O操作
        print(f"Coroutine {name} finished")
        return f"Result {name}"
    
    
    async def main():
        """主协程"""
        print("=== Asyncio Coroutines ===")
        
        start = time.time()
        
        # 并发执行多个协程
        results = await asyncio.gather(
            simple_coroutine("A", 1),
            simple_coroutine("B", 2),
            simple_coroutine("C", 1)
        )
        
        end = time.time()
        print(f"Total time: {end - start:.2f}s")
        print(f"Results: {results}")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(main())
    

    async和await关键字:

    import asyncio
    
    
    async def demonstrate_async_await():
        """演示async和await"""
        
        # async定义协程函数
        async def async_function():
            print("Async function started")
            await asyncio.sleep(1)
            print("Async function finished")
            return "Done"
        
        # await等待协程完成
        result = await async_function()
        print(f"Result: {result}")
        
        # await只能在async函数中使用
        # 普通函数中不能使用await
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(demonstrate_async_await())
    

    4.5.3 事件循环

    什么是事件循环?

    """
    事件循环(Event Loop):
    - asyncio的核心机制
    - 调度和执行所有协程
    - 处理I/O事件
    - 管理定时器和回调
    
    事件循环的工作流程:
    1. 检查是否有就绪的任务
    2. 执行就绪的任务
    3. 处理I/O事件
    4. 重复以上步骤
    """
    

    事件循环的使用:

    import asyncio
    
    
    async def task(name, delay):
        """异步任务"""
        print(f"Task {name} started")
        await asyncio.sleep(delay)
        print(f"Task {name} finished")
        return f"Result {name}"
    
    
    async def event_loop_demo():
        """事件循环示例"""
        # 获取当前事件循环
        loop = asyncio.get_running_loop()
        print(f"Current loop: {loop}")
        
        # 创建任务
        task1 = asyncio.create_task(task("A", 1))
        task2 = asyncio.create_task(task("B", 2))
        
        # 等待任务完成
        result1 = await task1
        result2 = await task2
        
        print(f"Results: {result1}, {result2}")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(event_loop_demo())		#这里就已经创建了事件循环
        '''
        等价于:
    
        创建一个事件循环
        注册主协程任务
        启动循环直到完成
        关闭事件循环
        '''
    

    4.5.4 并发执行任务

    使用asyncio.gather:

    import asyncio
    import time
    
    
    async def fetch_data(name, delay):
        """获取数据"""
        print(f"Fetching {name}...")
        await asyncio.sleep(delay)
        return f"Data {name}"
    
    
    async def gather_demo():
        """asyncio.gather示例"""
        print("=== asyncio.gather ===")
        
        start = time.time()
        
        # 并发执行多个协程
        results = await asyncio.gather(
            fetch_data("A", 1),
            fetch_data("B", 2),
            fetch_data("C", 1),
            fetch_data("D", 1)
        )
        
        end = time.time()
        print(f"Total time: {end - start:.2f}s")
        print(f"Results: {results}")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(gather_demo())
    

    使用asyncio.wait:

    import asyncio
    import time
    
    
    async def task(name, delay):
        """异步任务"""
        print(f"Task {name} started")
        await asyncio.sleep(delay)
        print(f"Task {name} finished")
        return f"Result {name}"
    
    
    async def wait_demo():
        """asyncio.wait示例"""
        print("=== asyncio.wait ===")
        
        start = time.time()
        
        # 创建任务
        tasks = [
            asyncio.create_task(task("A", 1)),
            asyncio.create_task(task("B", 2)),
            asyncio.create_task(task("C", 1))
        ]
        
        # 等待所有任务完成
        done, pending = await asyncio.wait(tasks)
        
        end = time.time()
        print(f"Total time: {end - start:.2f}s")
        print(f"Done tasks: {len(done)}")
        print(f"Pending tasks: {len(pending)}")
        
        # 获取结果
        results = [task.result() for task in done]
        print(f"Results: {results}")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(wait_demo())
    

    使用asyncio.as_completed:

    import asyncio
    import time
    
    
    async def task(name, delay):
        """异步任务"""
        print(f"Task {name} started")
        await asyncio.sleep(delay)
        print(f"Task {name} finished")
        return f"Result {name}"
    
    
    async def as_completed_demo():
        """asyncio.as_completed示例"""
        print("=== asyncio.as_completed ===")
        
        start = time.time()
        
        # 创建任务
        tasks = [
            asyncio.create_task(task("A", 1)),
            asyncio.create_task(task("B", 3)),
            asyncio.create_task(task("C", 2))
        ]
        
        # 按完成顺序处理任务
        for coro in asyncio.as_completed(tasks):
            result = await coro
            print(f"Completed: {result}")
        
        end = time.time()
        print(f"Total time: {end - start:.2f}s")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(as_completed_demo())
    

    4.5.5 超时控制

    使用asyncio.wait_for:

    import asyncio
    
    
    async def slow_task():
        """慢速任务"""
        print("Slow task started")
        await asyncio.sleep(5)
        print("Slow task finished")
        return "Done"
    
    
    async def timeout_demo():
        """超时控制示例"""
        print("=== Timeout Control ===")
        
        try:
            # 设置3秒超时
            result = await asyncio.wait_for(slow_task(), timeout=3.0)
            print(f"Result: {result}")
        except asyncio.TimeoutError:
            print("Task timed out!")
    
    
    # 使用示例
    if __name__ == "__main__":
        asyncio.run(timeout_demo())
    

    使用asyncio.timeout(Python 3.11+):

    import asyncio
    
    
    async def task(name, delay):
        """异步任务"""
        print(f"Task {name} started")
        await asyncio.sleep(delay)
        print(f"Task {name} finished")
        return f"Result {name}"
    
    
    async def timeout_context_manager_demo():
        """使用timeout上下文管理器"""
        print("=== Timeout Context Manager ===")
        
        try:
            async with asyncio.timeout(2.0):
                result = await task("A", 5)
                print(f"Result: {result}")
        except TimeoutError:
            print("Task timed out!")
    
    
    # 使用示例(需要Python 3.11+)
    # if __name__ == "__main__":
    #     asyncio.run(timeout_context_manager_demo())
    

    4.6 综合示例

    4.6.1 实现一个并发HTTP请求工具

    import asyncio
    import aiohttp
    import time
    from typing import List, Dict
    import logging
    
    logging.basicConfig(level=logging.INFO)
    
    
    class AsyncHTTPClient:
        """异步HTTP客户端"""
        
        def __init__(self, max_concurrent: int = 10):
            """
            初始化HTTP客户端
            
            Args:
                max_concurrent: 最大并发数
            """
            self.max_concurrent = max_concurrent
            self.semaphore = asyncio.Semaphore(max_concurrent)
        
        async def fetch(
            self,
            session: aiohttp.ClientSession,
            url: str,
            method: str = "GET",
            **kwargs
        ) -> Dict:
            """
            发送HTTP请求
            
            Args:
                session: aiohttp会话
                url: 请求URL
                method: 请求方法
                **kwargs: 其他请求参数
            
            Returns:
                Dict: 响应数据
            """
            async with self.semaphore:  # 限制并发数
                try:
                    async with session.request(method, url, **kwargs) as response:
                        data = await response.text()
                        return {
                            "url": url,
                            "status": response.status,
                            "data": data
                        }
                except Exception as e:
                    logging.error(f"Error fetching {url}: {e}")
                    return {
                        "url": url,
                        "error": str(e)
                    }
        
        async def fetch_multiple(self, urls: List[str]) -> List[Dict]:
            """
            并发获取多个URL
            
            Args:
                urls: URL列表
            
            Returns:
                List[Dict]: 响应列表
            """
            async with aiohttp.ClientSession() as session:
                tasks = [
                    self.fetch(session, url)
                    for url in urls
                ]
                results = await asyncio.gather(*tasks)
                return results
        
        async def fetch_with_timeout(
            self,
            url: str,
            timeout: float = 10.0
        ) -> Dict:
            """
            带超时的HTTP请求
            
            Args:
                url: 请求URL
                timeout: 超时时间
            
            Returns:
                Dict: 响应数据
            """
            try:
                async with asyncio.timeout(timeout):
                    async with aiohttp.ClientSession() as session:
                        async with session.get(url) as response:
                            data = await response.text()
                            return {
                                "url": url,
                                "status": response.status,
                                "data": data
                            }
            except asyncio.TimeoutError:
                logging.error(f"Timeout fetching {url}")
                return {
                    "url": url,
                    "error": "Timeout"
                }
            except Exception as e:
                logging.error(f"Error fetching {url}: {e}")
                return {
                    "url": url,
                    "error": str(e)
                }
    
    
    # 使用示例
    async def http_client_demo():
        """HTTP客户端演示"""
        client = AsyncHTTPClient(max_concurrent=5)
        
        urls = [
            "https://httpbin.org/get",
            "https://httpbin.org/delay/1",
            "https://httpbin.org/delay/2",
            "https://httpbin.org/status/200",
            "https://httpbin.org/status/404"
        ]
        
        print("=== Fetching Multiple URLs ===")
        start = time.time()
        results = await client.fetch_multiple(urls)
        end = time.time()
        
        print(f"\nTotal time: {end - start:.2f}s")
        print(f"Results: {len(results)} URLs")
        
        for result in results:
            if "error" in result:
                print(f"✗ {result['url']}: {result['error']}")
            else:
                print(f"✓ {result['url']}: {result['status']}")
        
        print("\n=== Fetching with Timeout ===")
        result = await client.fetch_with_timeout("https://httpbin.org/delay/5", timeout=2)
        print(f"Result: {result}")
    
    
    # 运行示例
    if __name__ == "__main__":
        asyncio.run(http_client_demo())
    

    4.6.2 实现一个并发DNS查询工具

    import asyncio
    import dns.asyncresolver
    from typing import List, Dict, Set
    import logging
    
    logging.basicConfig(level=logging.INFO)
    
    
    class AsyncDNSQuery:
        """异步DNS查询工具"""
        
        def __init__(self, max_concurrent: int = 50):
            """
            初始化DNS查询工具
            
            Args:
                max_concurrent: 最大并发数
            """
            self.max_concurrent = max_concurrent
            self.semaphore = asyncio.Semaphore(max_concurrent)
            self.resolver = dns.asyncresolver.Resolver()
        
        async def query_a_record(
            self,
            domain: str
        ) -> Dict:
            """
            查询A记录
            
            Args:
                domain: 域名
            
            Returns:
                Dict: 查询结果
            """
            async with self.semaphore:
                try:
                    answers = await self.resolver.resolve(domain, 'A')
                    return {
                        "domain": domain,
                        "type": "A",
                        "records": [str(rdata) for rdata in answers],
                        "status": "success"
                    }
                except dns.asyncresolver.NXDOMAIN:
                    return {
                        "domain": domain,
                        "type": "A",
                        "status": "not_found"
                    }
                except Exception as e:
                    logging.error(f"Error querying {domain}: {e}")
                    return {
                        "domain": domain,
                        "type": "A",
                        "status": "error",
                        "error": str(e)
                    }
        
        async def query_multiple(
            self,
            domains: List[str],
            record_type: str = "A"
        ) -> List[Dict]:
            """
            并发查询多个域名
            
            Args:
                domains: 域名列表
                record_type: 记录类型
            
            Returns:
                List[Dict]: 查询结果列表
            """
            if record_type == "A":
                tasks = [self.query_a_record(domain) for domain in domains]
            else:
                # 可以扩展其他记录类型
                tasks = [self.query_a_record(domain) for domain in domains]
            
            results = await asyncio.gather(*tasks)
            return results
        
        async def scan_subdomains(
            self,
            domain: str,
            subdomains: List[str]
        ) -> Dict:
            """
            扫描子域名
            
            Args:
                domain: 主域名
                subdomains: 子域名列表
            
            Returns:
                Dict: 扫描结果
            """
            full_domains = [f"{sub}.{domain}" for sub in subdomains]
            
            logging.info(f"Scanning {len(full_domains)} subdomains for {domain}")
            
            results = await self.query_multiple(full_domains)
            
            valid_subdomains = [
                result["domain"]
                for result in results
                if result["status"] == "success"
            ]
            
            return {
                "domain": domain,
                "total": len(full_domains),
                "found": len(valid_subdomains),
                "valid_subdomains": valid_subdomains,
                "details": results
            }
    
    
    # 使用示例
    async def dns_query_demo():
        """DNS查询演示"""
        dns_query = AsyncDNSQuery(max_concurrent=10)
        
        # 查询单个域名
        print("=== Query Single Domain ===")
        result = await dns_query.query_a_record("www.google.com")
        print(f"Result: {result}")
        
        # 查询多个域名
        print("\n=== Query Multiple Domains ===")
        domains = [
            "www.google.com",
            "www.github.com",
            "www.python.org",
            "nonexistent.example.com"
        ]
        
        results = await dns_query.query_multiple(domains)
        
        for result in results:
            if result["status"] == "success":
                print(f"✓ {result['domain']}: {result['records']}")
            elif result["status"] == "not_found":
                print(f"✗ {result['domain']}: Not found")
            else:
                print(f"✗ {result['domain']}: {result.get('error', 'Error')}")
        
        # 扫描子域名
        print("\n=== Scan Subdomains ===")
        subdomains = [
            "www", "mail", "ftp", "admin", "blog",
            "api", "dev", "test", "staging", "m"
        ]
        
        # 使用示例域名(实际使用时替换为目标域名)
        # scan_result = await dns_query.scan_subdomains("example.com", subdomains)
        # print(f"Found {scan_result['found']} valid subdomains")
        # for subdomain in scan_result['valid_subdomains']:
        #     print(f"  - {subdomain}")
    
    
    # 运行示例
    if __name__ == "__main__":
        asyncio.run(dns_query_demo())
    

    4.7 实践任务

    任务1:实现多线程下载器

    目标: 使用多线程实现一个文件下载器。

    要求:

    1. 支持多个文件并发下载
    2. 显示下载进度
    3. 处理下载错误
    4. 限制最大并发数
    5. 使用线程池

    代码框架:

    import threading
    import requests
    from concurrent.futures import ThreadPoolExecutor
    import os
    
    
    class MultiThreadDownloader:
        """多线程下载器"""
        
        def __init__(self, max_workers=5):
            # 在这里实现你的代码
            pass
        
        def download_file(self, url, save_path):
            # 在这里实现你的代码
            pass
        
        def download_multiple(self, urls, save_dir):
            # 在这里实现你的代码
            pass
    
    
    # 使用示例
    if __name__ == "__main__":
        downloader = MultiThreadDownloader(max_workers=3)
        urls = [
            "https://example.com/file1.txt",
            "https://example.com/file2.txt"
        ]
        downloader.download_multiple(urls, "downloads")
    

    任务2:实现线程安全的数据结构

    目标: 实现线程安全的队列和计数器。

    要求:

    1. 实现线程安全的FIFO队列
    2. 实现线程安全的计数器
    3. 实现线程安全的缓存
    4. 使用适当的锁机制
    5. 测试多线程环境下的正确性

    代码框架:

    import threading
    from collections import deque
    import time
    
    
    class ThreadSafeQueue:
        """线程安全的队列"""
        
        def __init__(self):
            # 在这里实现你的代码
            pass
        
        def put(self, item):
            # 在这里实现你的代码
            pass
        
        def get(self):
            # 在这里实现你的代码
            pass
        
        def size(self):
            # 在这里实现你的代码
            pass
    
    
    class ThreadSafeCounter:
        """线程安全的计数器"""
        
        def __init__(self, initial=0):
            # 在这里实现你的代码
            pass
        
        def increment(self):
            # 在这里实现你的代码
            pass
        
        def decrement(self):
            # 在这里实现你的代码
            pass
        
        def get_value(self):
            # 在这里实现你的代码
            pass
    
    
    # 使用示例
    if __name__ == "__main__":
        # 测试你的线程安全数据结构
        pass
    

    任务3:实现异步HTTP爬虫

    目标: 使用asyncio实现一个异步HTTP爬虫。

    要求:

    1. 使用aiohttp发送HTTP请求
    2. 支持并发请求
    3. 限制最大并发数
    4. 处理超时和错误
    5. 保存爬取结果

    代码框架:

    import asyncio
    import aiohttp
    from typing import List, Dict
    import time
    
    
    class AsyncWebCrawler:
        """异步Web爬虫"""
        
        def __init__(self, max_concurrent=10):
            # 在这里实现你的代码
            pass
        
        async def fetch_page(self, url):
            # 在这里实现你的代码
            pass
        
        async def crawl_multiple(self, urls):
            # 在这里实现你的代码
            pass
        
        async def crawl_with_retry(self, url, max_retries=3):
            # 在这里实现你的代码
            pass
    
    
    # 使用示例
    if __name__ == "__main__":
        async def main():
            crawler = AsyncWebCrawler(max_concurrent=5)
            urls = [
                "https://example.com/page1",
                "https://example.com/page2"
            ]
            results = await crawler.crawl_multiple(urls)
            print(results)
        
        asyncio.run(main())
    

    任务4:实现生产者消费者模型

    目标: 使用多线程实现生产者消费者模型。

    要求:

    1. 实现生产者线程
    2. 实现消费者线程
    3. 使用线程安全队列
    4. 控制生产和消费速度
    5. 正确处理线程结束

    代码框架:

    import threading
    import queue
    import time
    import random
    
    
    class ProducerConsumerModel:
        """生产者消费者模型"""
        
        def __init__(self, max_size=10):
            # 在这里实现你的代码
            pass
        
        def producer(self, name, items):
            # 在这里实现你的代码
            pass
        
        def consumer(self, name):
            # 在这里实现你的代码
            pass
        
        def start(self, num_producers, num_consumers):
            # 在这里实现你的代码
            pass
    
    
    # 使用示例
    if __name__ == "__main__":
        model = ProducerConsumerModel(max_size=10)
        model.start(num_producers=2, num_consumers=3)
    

    任务5:综合实践

    目标: 综合运用所学知识,实现一个并发工具。

    要求:

    1. 实现一个并发任务调度器
    2. 支持多线程和异步两种模式
    3. 支持任务优先级
    4. 支持任务超时控制
    5. 支持任务重试机制
    6. 实现任务结果缓存

    代码框架:

    import asyncio
    import threading
    from concurrent.futures import ThreadPoolExecutor
    from typing import Callable, Any, Dict
    import time
    
    
    class ConcurrentTaskScheduler:
        """并发任务调度器"""
        
        def __init__(self, mode="async", max_workers=10):
            # 在这里实现你的代码
            pass
        
        def submit_task(self, func, *args, priority=0, timeout=None, max_retries=0, **kwargs):
            # 在这里实现你的代码
            pass
        
        async def run_async(self):
            # 在这里实现你的代码
            pass
        
        def run_threaded(self):
            # 在这里实现你的代码
            pass
        
        def get_results(self):
            # 在这里实现你的代码
            pass
    
    
    # 使用示例
    if __name__ == "__main__":
        # 测试你的任务调度器
        pass
    

    4.8 本课总结

    本课重点内容回顾

    1. 进程与线程

    • 进程的定义和特点
    • 线程的定义和特点
    • 多进程 vs 多线程的对比
    • Python中的多进程和多线程实现
    • 进程间通信和线程间共享数据

    2. GIL机制

    • GIL的定义和作用
    • GIL对多线程的影响
    • CPU密集型 vs I/O密集型任务
    • 如何绕过GIL限制(多进程、C扩展、asyncio)

    3. threading模块

    • 创建和启动线程
    • 线程属性和方法
    • 守护线程
    • 线程间通信(Queue、Event、Condition)

    4. 线程同步与锁

    • 竞争条件和线程安全问题
    • Lock和RLock的使用
    • Semaphore和BoundedSemaphore
    • 超时获取锁

    5. asyncio异步编程

    • asyncio的基本概念
    • 协程(async/await)
    • 事件循环
    • 并发执行任务(gather、wait、as_completed)
    • 超时控制

    下节课预告

    第5课:OneForAll整体架构分析

    • 项目整体设计
    • 模块化架构
    • 数据流和处理流程
    • 配置管理系统
    • 日志系统设计
    • 入口文件解析

    课后思考

    1. 为什么Python要引入GIL?GIL对程序性能有什么影响?
    2. 在什么情况下应该使用多线程,什么情况下应该使用多进程?
    3. asyncio相比多线程有什么优势?
    4. 如何避免死锁?
    5. 在OneForAll中,哪些部分适合使用多线程,哪些部分适合使用异步编程?

    推荐阅读


    4.9 附录

    附录A:线程安全速查表

    """
    线程安全数据结构和方法:
    
    1. Queue(线程安全队列)
       - queue.Queue() - FIFO队列
       - queue.LifoQueue() - LIFO队列
       - queue.PriorityQueue() - 优先队列
       - 方法:put(), get(), task_done(), join()
    
    2. 锁
       - threading.Lock() - 普通锁
       - threading.RLock() - 可重入锁
       - threading.Semaphore(n) - 信号量
       - threading.BoundedSemaphore(n) - 有界信号量
    
    3. 同步原语
       - threading.Event() - 事件
       - threading.Condition() - 条件变量
       - threading.Barrier(n) - 屏障
    
    4. 线程安全的数据结构
       - queue.Queue
       - collections.deque(部分操作需要加锁)
       - threading.local() - 线程局部存储
    """
    

    附录B:asyncio速查表

    """
    asyncio常用函数和类:
    
    1. 协程定义和执行
       - async def func(): await something
       - asyncio.run(coro) - 运行协程
       - asyncio.create_task(coro) - 创建任务
    
    2. 并发执行
       - asyncio.gather(*coros) - 并发执行多个协程
       - asyncio.wait(tasks) - 等待任务完成
       - asyncio.as_completed(tasks) - 按完成顺序处理
    
    3. 超时控制
       - asyncio.wait_for(coro, timeout) - 带超时的等待
       - async with asyncio.timeout(n): - 超时上下文
    
    4. 同步原语
       - asyncio.Lock() - 异步锁
       - asyncio.Event() - 异步事件
       - asyncio.Semaphore(n) - 异步信号量
       - asyncio.Condition() - 异步条件变量
    
    5. 队列
       - asyncio.Queue() - 异步队列
       - asyncio.LifoQueue() - 异步LIFO队列
       - asyncio.PriorityQueue() - 异步优先队列
    """
    

    附录C:并发模式速查表

    """
    常见并发模式:
    
    1. 生产者-消费者模式
       - 使用Queue进行通信
       - 生产者放入数据,消费者取出数据
       - 适用于解耦生产和消费
    
    2. 线程池模式
       - 使用ThreadPoolExecutor
       - 复用线程,减少创建开销
       - 限制最大并发数
    
    3. Future模式
       - 使用concurrent.futures.Future
       - 异步获取任务结果
       - 支持回调函数
    
    4. 资源池模式
       - 使用Semaphore限制并发
       - 管理有限资源
       - 如数据库连接池
    
    5. Pipeline模式
       - 数据分阶段处理
       - 每个阶段由不同线程/协程处理
       - 提高吞吐量
    """
    

    附录D:学习检查清单


    恭喜你完成了第4课的学习!🎉

    现在你已经掌握了并发编程的基础知识,包括进程与线程、GIL机制、threading模块、线程同步、asyncio异步编程等。这些都是开发OneForAll高性能并发处理功能所必需的技能。

    在下一课中,我们将深入学习OneForAll的整体架构,理解项目的设计思想和实现原理。

    记住: 并发编程是实践性很强的技能,一定要动手完成所有的实践任务!

    继续加油,我们下节课见!💪

    posted @ 2026-04-27 14:23  羽弥YUMI  阅读(16)  评论(0)    收藏  举报