zoukankan      html  css  js  c++  java
  • 第三十章 网路编程------线程

    1.什么是线程

      线程是操作系统最小的运算调度单位,被包含在进程中,一个线程就是一个固定的执行流程

    线程和进程的关系 :

      线程不能单独存在,必须存在与进程中

      进程是一个资源单位,其包含了运行程序所需的所有资源

      线程才是真正的执行单位

      没有线程,进程中的资源无法被利用起来,所以一个进程至少包含一个线程,称之为主线程

      当开启一个程序时,操作系统就会为自己创建一个主线程

      线程可以有程序后期开启,自己开启线程称之为子线程

    为什么需要线程:

      目的:提高效率

      就像以一个车间,如果产量跟不上,就再创建一条流水线

      也可以再造一个新车间,那需要把原料运过去,这个过程是非常耗时的

      所以通常情况是创建新的流水线,而不是车间 即 线程

    如何使用:

    使用方法与进程一样

    开启线程的代码可以放在任何位置,开启进程必须放在判断下面

    from threading import Thread,current_thread
    import time

    def task():
    print("2",current_thread())
    print("子线程running")
    time.sleep(10)
    print("子线程over")

    # 使用方法一 直接实例化Thread类
    if __name__ == '__main__':
      t = Thread(target=task)
      t.start()

      # task()
      # 执行顺序不固定 如果开启线程速度足够快 可能子线程先执行
      print("主线程over")
      print("1",current_thread())

    # 使用方法二 继承Thread 覆盖run方法
    class MyThread(Thread):
      def run(self):
        print("子线程run!")
    m = MyThread()
    print("主线over")

    # 使用方法和多进程一模一样 开启线程的代码可以放在任何位置 开启进程必须放在判断下面

    线程的特点:

      创建开销小

      同一个进程中的多个线程数据是共享的

      多个线程之间,是平等的没有父子关系   所有线程的PID都是相同的

    # 创建线程开销对比
    import os
    from threading import Thread
    from multiprocessing import Process

    import time


    def task():
      # print("hello")
      print(os.getpid())
      pass

    if __name__ == '__main__':

      st_time = time.time()

      ts = []
      for i in range(100):
        t = Thread(target=task)
        # t = Process(target=task)
        t.start()
        ts.append(t)

      for t in ts:
        t.join()

    print(time.time()-st_time)
    print("主over")

    守护线程

      一个线程可以设置为另一个线程的守护线程

      特点:被守护线程结束后守护线程也随之结束

      守护线程会等到所有非守护线程结束后结束,前提是除了主线程之外,还有别的非守护线程

      当然如果守护线程已经完成任务,立马就结束了 

    from threading import Thread
    import time

    def task():
      print("子1running......")
      time.sleep(100)
      print("子1over......")

    def task2():
      print("子2running......")
      time.sleep(4)
      print("子2over......")

    t = Thread(target=task)
    t.daemon = True
    t.start()

    t2 =Thread(target=task2)
    t2.start()

    print("主over")

    线程互斥锁

      共享意味着竞争

      线程中也存在安全问题

      多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题

      解决方案:互斥锁

    from threading import Thread,enumerate,Lock
    import time

    number = 10

    lock = Lock()

    def task():
      global number
      lock.acquire()
      a = number
      time.sleep(0.1)
      number = a - 1
      lock.release()

    for i in range(10):
      t = Thread(target=task)
      t.start()

    for t in enumerate()[1:]:
      # print(t)
      t.join()

    print(number)

    死锁问题

    from threading import Lock, current_thread, Thread

    """
      死锁问题
      当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源 要想使用必须同时具备两把锁
      这时候程序就会进程无限卡死状态 ,这就称之为死锁
      例如:
          要吃饭 必须具备盘子和筷子   但是一个人拿着盘子 等筷子 另一个人拿着筷子等盘子
       
      如何避免死锁问题  
          锁不要有多个,一个足够
          如果真的发生了死锁问题,必须迫使一方先交出锁
           
    """
    import time
    # 盘子
    lock1 = Lock()

    # 筷子
    lock2 = Lock()

    def eat1():
       lock1.acquire()
       print("%s抢到了盘子" % current_thread().name)
       time.sleep(0.5)
       lock2.acquire()
       print("%s抢到了筷子" % current_thread().name)

       print("%s开吃了!" % current_thread().name)
       lock2.release()
       print("%s放下筷子" % current_thread().name)

       lock1.release()
       print("%s放下盘子" % current_thread().name)


    def eat2():
       lock2.acquire()
       print("%s抢到了筷子" % current_thread().name)

       lock1.acquire()
       print("%s抢到了盘子" % current_thread().name)


       print("%s开吃了!" % current_thread().name)


       lock1.release()
       print("%s放下盘子" % current_thread().name)
       lock2.release()
       print("%s放下筷子" % current_thread().name)


    t1 = Thread(target=eat1)


    t2 = Thread(target=eat2)

    t1.start()
    t2.start()

    可重入锁 了解

    Rlock 称之为递归锁或者可重入锁

    Rlock不是用来解决死锁问题的

    与Lock唯一的区别: Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次 如果一个线程已经执行过acquire 其他线程将无法执行acquire

     


    from threading import RLock, Lock, Thread

    # l = Lock()
    #
    # l.acquire()
    # print("1")
    # l.acquire()
    # print("2")


    l = RLock()

    # l.acquire()
    # print("1")
    # l.acquire()
    # print("2")

    def task():
       l.acquire()
       print("子run......")
       l.release()


    # 主线程锁了一次
    l.acquire()
    l.acquire()

    l.release()
    l.release()
    t1 = Thread(target=task)
    t1.start()

    信号量 了解


    """
    信号量 了解
    Lock RLock

    可以现在被锁定的代码 同时可以被多少线程并发访问
    Lock 锁住一个马桶 同时只能有一个
    Semaphore 锁住一个公共厕所   同时可以来一堆人


    用途: 仅用于控制并发访问   并不能防止并发修改造成的问题
    """

    from threading import Semaphore, Thread
    import time

    s = Semaphore(5)
    def task():
      s.acquire()
      print("子run")
      time.sleep(3)
      print("子over")
      s.release()

    for i in range(10):
      t = Thread(target=task)
      t.start()

     

     

  • 相关阅读:
    LeetCode 面试题 02.02. 返回倒数第 k 个节点
    LeetCode 1290. 二进制链表转整数
    LeetCode 面试题52. 两个链表的第一个公共节点
    LeetCode 2. 两数相加
    Jupyter Notebook 常用快捷键 (转)
    LeetCode 414. 第三大的数
    LeetCode 404. 左叶子之和
    三年了
    LeetCode 543. 二叉树的直径
    求结点在二叉排序树中层次的算法
  • 原文地址:https://www.cnblogs.com/sry622/p/10974544.html
Copyright © 2011-2022 走看看