多线程 -- threading

多线程模块 threading

  • 创建多线程的两种方式:

    
    import threading
    import time
    
    
    
  • 创建线程的第一种方式

    def foo(n):
        pass
    print('hello world')
        
    t1 = threading.Thread(target=foo, args=(1,))
    t1.start()
    
  • 创建线程的第二种方式

``` 
class MyThread(threading.Thread):

    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num   # 对象里的字段  # self 是 t1或t2

    def run(self):

        print("running on number: %s" % self.num)

        time.sleep(3)

if __name__ == '__main__':
    t1 = MyThread(1)  # 实例化一个类的对象,执行构造方法
    t2 = MyThread(2)

    t1.start()
    t2.start()
``` 
  • 创建线程:
    import threading
    t1 = threading.Thread(target=music, args=('七里香',))
    
    target指向函数,args指向函数的参数
  • 启动线程:

      t.start()
    
  • 阻塞线程:

      t.join()    阻塞直到线程t结束   
    
  • 多线程实例1

      import threading
      from time import ctime, sleep
      import time
          
      # 预计耗时4秒
      def music(func):
          for i in range(2):
              print("I was listening to %s. %s" % (func, ctime()))
              sleep(2)
              print("end listening %s" %ctime())
      
      # 预计耗时6秒
      def movie(func):
          for i in range(2):
              print("Begin watching at the %s! %s" % (func,ctime()))
              sleep(3)
              print("end watching %s" % ctime())
      
      
      # 创建线程1,2
      
      threads = []
      t1 = threading.Thread(target=music, args=('七里香',))
      threads.append(t1)
      t2 = threading.Thread(target=movie, args=('十三区',))
      threads.append(t2)
      
      
      if __name__ == '__main__':
          for t in threads:
              t.start()
          start = time.time()
          t2.join()
          end = time.time()
      
      
          # t2.join()    # join阻塞
          print("总共耗时 %s" % (end-start))
          
          
      # 结果:总共耗时 6.004828929901123
    
  • 多线程 -- 计算密集型

    import threading
    import time
    
    begin = time.time()
    
    def add(n):
        sum = 0
        for i in range(n):
            sum += i
        print(sum)
    
    
    # 单线程串行计算
    # add(10000000)
    # add(10000000)
    
    
    # 多线程并行计算
    t1 = threading.Thread(target=add, args=(10000000,))
    t1.start()
    # print('1开始了')
    
    t2 = threading.Thread(target=add, args=(10000000,))
    t2.start()
    # print('2也开始了')
    
    t1.join()
    t2.join()
    #
    end = time.time()
    
    print(end-begin)
    
    
    # 串行花费 14.73 秒  两者都是计算密集型,都在抢CPU
    # 并行花费 15.71 秒  并行反而更多,因为切换还需要时间
    
    # IO密集型任务或函数
    # 计算密集型任务
    
    # GIL全局解释锁  如果只有一颗CPU,无法解决计算密集型的任务 只有Cpython有这个bug
    
  • 多线程 -- IO密集型

    import time
    import threading
    
    
    def foo(n):                         # 设定3秒
        print('线程1开始')
        print('foo %s' % n)
        # print('foo')
        time.sleep(3)
        print('线程1结束\n')
    
    
    def bar(n):                         # 设定1秒
        print('线程2开始')
        print('bar %s' % n)
        time.sleep(1)
        # print('ok')
        print('线程2结束')
    
    
    # t1 t2 即为线程
    # target = 要执行的函数 args = 参数
    t1 = threading.Thread(target=foo, args=(1,))
    t2 = threading.Thread(target=bar, args=(2,))
    
    print('...... in the main  ........')
    
    # 线程执行 start()
    
    begin = time.time()
    
    t1.start()  # 线程开始
    t2.start()  # 线程开始
    
    t1.join()  # 子线程不结束不往下走
    t2.join()  # 子线程不结束不往下走
    
    end = time.time()
    print('整个程序一共花了', end - begin, '秒,asshole')  #
    
    
    # 运行结果: 整个程序一共花了 3.003476858139038 秒,asshole
        
    
  • 死锁

    # 死锁怎么办?
    # 用递归锁解决死锁问题,递归锁可重用
    
    import threading, time
    
    class myThread(threading.Thread):
    
    def doA(self):
        # lockA.acquire()
        lock.acquire()                  # 加锁        # 为什么在外面加了一把锁后还要在里面再加一把锁
        print(self.name, "gotlockA", time.ctime())
        time.sleep(1)
        # lockB.acquire()
        lock.acquire()                  # 加第二把锁
        print(self.name, "gotlockB", time.ctime())
        # lockB.release()
        lock.release()                  # 释放第一把锁
        # lockA.release()
        lock.release()                  # 释放第二把锁
    
    def doB(self):
        lock.acquire()
        print(self.name, "gotlockB", time.ctime())
        time.sleep(1)
        lock.acquire()
        print(self.name, "gotlockA", time.ctime())
        lock.release()
        lock.release()
    
    def run(self):   # 类似于构造方法
        self.doA()
        self.doB()
    
    
    if __name__ == "__main__":
    
        # lockA = threading.Lock()     # 普通锁
        # lockB = threading.Lock()
        lock = threading.RLock()       # Rlock 叫递归锁,可重用
        threads = []
        for i in range(5):
            threads.append(myThread())
        for t in threads:
            t.start()
        for t in threads:
            t.join()  # 等待线程结束,后面再讲。
    
    
  • 同步锁

        # 加锁后会加锁的部分变成串行
    
    import time
    import threading
    
    def addNum():
        global num  # 在每个线程中都获取这个变量
        print('fuck off')
        # num -= 1          #  此操作的时间远小于CPU切换的时间
    
        # 加锁,被加锁的部分是串行
    
        r.acquire()         #######  加锁
        temp = num          # 1
        # time.sleep(0.001)   # 2 有可能取了数99后,执行完这两步后CPU转到另外的线程上去了,
        print('ok')                    # 另外的线程取到99,执行减1,CPU再转回当前线程,又执行99-1,重复了
        time.sleep(0.0002)
        num = temp - 1
        r.release()         ######## 释放锁
    
    
    
    num = 100
    thread_list = []
    
    r = threading.Lock()    # python的GIL锁
    
    # 用for循环创建100个线程
    for i in range(100):
        t = threading.Thread(target=addNum)
        t.start()
        # t.join()     # join阻塞,可以得到正确的结果,从但是变成了串行,失去了多线程的意义
                       # join虽然可以得到正确结果,但是除了计算的其他部分也会变成并行
        thread_list.append(t)
    
    
    for t in thread_list:
        t.join()
    
    
    print("\nfinal num:", num)
    
    
    # num减1的速度如果
    
    # GIL保证只有一个线程进入解释器
    # 自己加的锁是锁CPU,在我释放锁之前你不要切换了
    
    
  • event

    # event 类似condition
    
    # event.isSet():返回event的状态值;
    #
    # event.wait():如果 event.isSet()==False将阻塞线程;
    #
    # event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
    #
    # event.clear():恢复event的状态值为False。
    
    
    import threading, time
    
    class Boss(threading.Thread):
        def run(self):
            print("BOSS: 今晚大家都要加班到22:00")
            event.is_set() or event.set()
            time.sleep(2)
            print("BOSS:<22:00>可以下班了。 ")
            event.is_set() or event.set()
    
    class Worker(threading.Thread):
        def run(self):
            event.wait()
            print("Worker:哎,命苦啊")
            time.sleep(0.25)
            event.clear()
            event.wait()
            print("Worker: OhYear!")
    
    
    
    
    
    if __name__ == "__main__":
        event = threading.Event()
        threads = []
        for i in range(5):
            threads.append(Worker())
        threads.append(Boss())
        for t in threads:
            t.start()
        for t in threads:
            t.join()
    
    
  • 多线程利器 QUEUE队列

        # 队列里本身就有一把锁
    #
    # import queue, time, threading
    #
    # d = queue.Queue(3)   #
    
    #  d.put('jinxing',0)  #插入数据
    # d.put('xiaohu')
    # d.put('haoran')
    #
    # print(d.get())
    # print(d.get())
    # print(d.get())
    #
    #
    # print(d.qsize())
    
    # li = [1,2,3,4,5]
    #
    # def pri():
    #     while li:
    #         a = li[-1]
    #         print(a)
    #         time.sleep(1)
    #         try:
    #             li.remove(a)
    #         except:
    #             print('----',a)
    #
    # t1 = threading.Thread(target=pri, args=())
    # t1.start()
    # t2 = threading.Thread(target=pri, args=())
    # t2.start()
    
    import threading, queue
    from time import sleep
    from random import randint
    
    
    class Production(threading.Thread):   #  生产者
        def run(self):
            while True:
                r = randint(0, 100)
                q.put(r)
                print("生产出来%s号包子" % r)
                sleep(1)
    
    
    class Proces(threading.Thread):       #  消费者
        def run(self):
            while True:
                re = q.get()
                print("吃掉%s号包子" % re)
                sleep(1)
    
    
    if __name__ == "__main__":
        q = queue.Queue(10)
        threads = [Production(), Production(), Production(), Proces()]
        for t in threads:
            t.start()
    
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 线程状态新建,就绪,运行,阻塞,死亡。 线程同步多线程可以同时运行多个任务,线程需要共享数据的时候,可能出现数据不...
    KevinCool阅读 793评论 0 0
  • 我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程。多线程优点: 在一个进程中的多线程和主线程分享相同的...
    第八共同体阅读 514评论 0 0
  • 线程 引言&动机 考虑一下这个场景,我们有10000条数据需要处理,处理每条数据需要花费1秒,但读取数据只需要0....
    不浪漫的浪漫_ea03阅读 358评论 0 0
  • 引言&动机 考虑一下这个场景,我们有10000条数据需要处理,处理每条数据需要花费1秒,但读取数据只需要0.1秒,...
    chen_000阅读 501评论 0 0
  • 1.进程和线程 队列:1、进程之间的通信: q = multiprocessing.Queue()2、...
    一只写程序的猿阅读 1,098评论 0 17