zoukankan      html  css  js  c++  java
  • Python并发复习1

    一、基本概念

    程序: 指令集,静态,

    进程: 当程序运行时,会创建进程,是操作系统资源分配的基本单位

    线程: 进程的基本执行单元,每个进程至少包含一个线程,是任务调度和执行的基本单位

    > 进程和线程之间的关系:


    ① 一个线程只属于一个进程
    ② 一个进程可以包含多个线程,只有一个主线程


    >  进程和线程资源对比

    ① 进程具有独立的空间和系统资源

    ② 线程不具有独立的空间和系统资源

    ③ 同一个进程下的多个线程共享该进程的空间和系统资源

    ④ 局部变量不共享

    > 多线程中对于贡献资源修改的问题 
    --- 多线程的同步问题、 线程不安全、通过同步解决


    二、 多线程

    1.需要清楚的一点

      单核CPU: 宏观并行,微观实际上是串行 - 并发
      多核CPU: 微观本质并行

    2.应用场合:  

      ① 计算密集型  --- 不适合单核CPU多线程  --- 数值计算
      ② I/O密集型  --- 适合单核CPU多线程   --- 频繁读写

    3.优点:

       速度快

    4.缺点:

      (1) 线程本身也是程序,线程越多,占用的内存越多;
      (2) 多线程的调用需要协调管理,CPU对线程的跟踪需要消耗内存;
      (3) CPU多线程的切换需要消耗内存
      (4) 多线程之间对共享资源问题,需要解决数据的一致性

    三、 线程的创建

    三种方式:


    (1) threading模块
    --- 通过指定target(函数名)和args(函数参数)
    (2) 使用Thread类,重写run方法
    (3) 使用线程池

    3.1 threading模块

     1 import threading
     2 import time
     3 def misson(*args):
     4     for i in range(args[1]):
     5         print(i)
     6         time.sleep(1)
     7 # 创建线程对象,参数必须使用元组传递
     8 t = threading.Thread(target = mission, args = args)
     9 # 激活线程(排队),等待CPU分配时间片来执行
    10 t.start()
    11 t.start()

    3.2. 使用Thread类,重写run方法 

            --- 适用于需要创建很多个执行方法相同的线程对象时,用类方法

     1 class My_Thread(threading.Thread):
     2     def __init__(self, n1):
     3         self.n1 = n1
     4         super().__init__()
     5     # run方法是真正执行函数认为的方法
     6     def run(self):
     7         for i in range(self.end):
     8             print(i)
     9 t1 = My_Thread()
    10 t1.start(10)

    3.3 线程池

    线程池的使用threadpool较少,使用concurrent.futures下的 ThreadPoolExecutor 线程池

     1 from concurrent.futures import ThreadPoolExecutor
     2 import time
     3 
     4 
     5 def sayhello(a):
     6     print("hello: " + a)
     7     time.sleep(2)
     8 
     9 
    10 def main():
    11     seed = ["a", "b", "c"]
    12 
    13     # 第一种方法submit
    14     with ThreadPoolExecutor(3) as executor:
    15         for each in seed:
    16             executor.submit(sayhello, each)
    17 
    18     # 第二种方法map
    19     with ThreadPoolExecutor(3) as executor1:
    20         executor1.map(sayhello, seed)
    21 
    22 
    23 if __name__ == '__main__':
    24     main()

    四、 线程的生命周期

    (1) 新建 --- 创建线程对象,没有执行能力
    (2) 就绪 --- 调用start方法,把执行权利交给CPU
    (3) 运行 --- 执行线程任务,获得CPU时间片在一个线程运行时,可能将时间片分配给其他线程
    (4) 阻塞 --- 处于等待过程,CPU不给阻塞状态分配时间片
    (5) 死亡 --- run方法执行完毕或者抛出没有捕获的异常

    五、线程的同步

      --- 在同一个进程下,各个线程共享资源引起不安全,即对成员变量的操作进行共享

    1.  抢票问题 - 锁

     1 import time
     2 import threading
     3 
     4 ticket = 100
     5 
     6 def buy_ticket():
     7     global ticket
     8     while ticket:
     9         t = threading.current_thread()
    10         print(f'{t.name}{ticket}')
    11         time.sleep(0.5)
    12         ticket -= 1
    13 
    14 if __name__ == '__main__':
    15     t1 = threading.Thread(target=buy_ticket)
    16     t1.name = '张三'  # 设定线程名字
    17     t1.start()
    18     t2 = threading.Thread(target=buy_ticket)
    19     t2.name = '张四'
    20     t2.start()
    21     t3 = threading.Thread(target=buy_ticket)
    22     t3.name = '张五'
    23     t3.start()

    运行结果如下,会出现重复的抢票,即多个线程获得同一个变量:

    解决办法:

          使用线程锁, 即在同一时间内,一个共享资源只能被一个线程访问

    加锁      --- threading.Lock()
    抢锁     --- lock.acquare()
    解锁     --- lock.release()

     1 import time
     2 import threading
     3 
     4 lock = threading.Lock()
     5 ticket = 100
     6 def buy_ticket():
     7     global ticket
     8     while True:
     9         try:
    10             lock.acquire()
    11             if ticket > 0:
    12                 t = threading.current_thread()
    13                 time.sleep(0.2)
    14                 print(f'{t.name}抢到了第{ticket}张票')
    15                 ticket -= 1
    16             else:
    17                 break
    18         finally:
    19             lock.release()
    20 
    21 t1=threading.Thread(target=buy_ticket)
    22 t1.name="张三"
    23 t2=threading.Thread(target=buy_ticket)
    24 t2.name="李四"
    25 t3=threading.Thread(target=buy_ticket)
    26 t3.name="王五"
    27 
    28 t1.start()
    29 t2.start()
    30 t3.start()

    2. 生产者消费者模型

       (1)  消费者一直消费,商品=0,等待生产                    --- wait 
       (2)  生产者隔一段时间看一次,如果小于3,开始生产 --- 耗费CPU
       (3)  只要消费者消费了产品,通知生产者生产商品       --- notify

       程序见Python并发复习2 - threading模块

    六、多进程

    1. 进程创建

    (1)使用multiprocessing.Process(target=函数名)

    (2)继承Process重写run


    2. 进程操作

    Os.getpid      # 得到本身进程id

    Os.getppid    # 得到父进程id

    Fork:复制进程,只能在linux下使用

    其他方法同线程

    3. 进程队列

    进程优于线程:

    不存在资源共享问题,没有同步锁,也没有死锁

    多进程需要处理资源共享问题,使用队列序列化处理(进程队列已经处理好)

       程序见Python并发复习2 - threading模块

  • 相关阅读:
    C# 轻松读取、改变文件的创建、修改、访问时间 z
    C#中将dll汇入exe z
    ASP.NET中引用dll“找不到指定模块"的完美解决办法 z
    C# 调用第三方DLL z
    [ACM_贪心] Radar Installation
    Beauty Contest
    [ACM_几何] Wall
    [ACM_几何] Pipe
    [ACM_几何] Fishnet
    [ACM_动态规划] 找零种类
  • 原文地址:https://www.cnblogs.com/geoffreyone/p/9870220.html
Copyright © 2011-2022 走看看