zoukankan      html  css  js  c++  java
  • Python线程详解

    Python线程详解

        # 进程的三状态:就绪 运行 阻塞
        # multiprocessing模块
            # Process-开启进程
            # Lock - 互斥锁
                # 为什么要在进程中加锁
                    # 因为进程操作文件也会发生数据不安全
            # Queue -队列 IPC机制(Pipe,redis,memcache,rabbitmq,kafka)
                # 生产者消费者模型
            # Manager - 提供数据共享机制

    ------------------Process-开启进程----------
    可查看链接https://www.cnblogs.com/Marcki/p/10111927.html
    ---------线程学习--------
    1、启动线程start
    线程的异步

    2、开启多个子线程
    3、join方法
    4、测试
    进程和线程的开启效率差
    数据隔离还是共享
    5、守护线程


    1)启动线程start

    (1从线程导入线程 2实例化Thread,传递线程函数。3对象.start())

    ```
    import os
    from threading import Thread
    #multiprocessing完全是仿照threading类写的
    def func():
    print(os.getpid())
    #启动线程 start
    Thread(target=func).start()
    print('---->',os.getpid())
    -------------结果:
    5804
    ----> 5804

    ```
    #由上可知,1、主线程和子线程在同一个进程里,pid一致。2、在Windows里面不需要写if name=='main'了。3、先打印子线程里的内容,再打印主线程里内容,与进程相反,说明线程开启快,快到主线程还没执行下一句代码这个子线程就创建并执行了。

    2)线程是异步的,并发的

    ```

    import os,time
    from threading import Thread
    def func():
    print('start son thread')
    time.sleep(1)
    print('end son thread')
    Thread(target=func).start()
    print('start',os.getpid())
    time.sleep(0.5)
    print('end',os.getpid())
    --------------结果:
    start son thread
    start 5280
    end 5280
    end son thread

    ```

    3)开启多个子线程

    import os,time
    from threading import Thread
    def func():
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid())
    for i in range(3):
    Thread(target=func).start()
    ----------------结果:
    start son thread
    start son thread
    start son thread
    end son thread 6772
    end son thread 6772
    end son thread 6772

    4)往线程函数里传参,通过args,和进程一样。线程的调度仍然是操作系统决定的,谁的时间片到了就运行谁的

    ```

    import os,time
    from threading import Thread
    def func(arg):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid(),arg)
    for i in range(3):
    Thread(target=func,args=(i,)).start()
    ------------结果:
    start son thread
    start son thread
    start son thread
    end son thread 7112 0
    end son thread 7112 1
    end son thread 7112 2

    ```

    5)1、主线程等待所有子线程结束之后才结束。2、主线程如果结束了,主进程也就结束了。

    import os,time
    from threading import Thread
    def func(arg):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid(),arg)
    for i in range(3):
    Thread(target=func,args=(i,)).start()
    print("main")
    --------------结果:
    start son thread
    start son thread
    start son thread
    main #主线程代码执行完了,等待子线程结束
    end son thread 5416 0
    end son thread 5416 1
    end son thread 5416 2
    Process finished with exit code 0 #所有子线程结束,主线程才结束,然后主进程结束
    5)[1]join方法 阻塞 直到子线程执行结束
    #用join,那么线程对象和start就不要放在一起了,单执行对象.start()来开启
    import os,time
    from threading import Thread
    def func(arg):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid(),arg)
    t=Thread(target=func,args=(0,))
    t.start()
    t.join()
    print("子线程执行结束!")
    ----------------------结果:
    start son thread
    end son thread 6756 0
    子线程执行结束!
    [2]创建多个子线程,t.join()在循环外,这时t代表for循环最后一个值3,所有只是阻塞最后一个创建的t对象。所以每次打印“子线程执行结束!”都是在“end son thread 4864 3”之后。但是这时执行慢的子线程就没被阻塞就开始执行主线程中代码了。
    import os,time
    from threading import Thread
    def func(arg):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid(),arg)
    for i in range(4):
    t=Thread(target=func,args=(i,))
    t.start()
    t.join()
    print("子线程执行结束!")
    --------------结果:
    start son thread
    start son thread
    start son thread
    start son thread
    end son thread 4864 0
    end son thread 4864 2
    end son thread 4864 3
    子线程执行结束!
    end son thread 4864 1
    [3]保证所有子线程都结束之后再继续执行主线程中的代码
    #注:将所有线程对象都追加到列表,循环列表,将每个对象.join阻塞。所有线程对象执行结束然后才执行主线程中程序
    import os,time
    from threading import Thread
    def func(arg):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid(),arg)
    li=[]
    for i in range(4):
    t=Thread(target=func,args=(i,))
    t.start()
    li.append(t)
    for t in li:t.join()
    print("子线程执行结束!")
    --------------结果:
    start son thread
    start son thread
    start son thread
    start son thread
    end son thread 6480 0
    end son thread 6480 1
    end son thread 6480 2
    end son thread 6480 3
    子线程执行结束!

    6)[1]使用面向对象的方式启动线程

    #注意:用自己类创建的对象记得start开启线程
    #1、继承Thread类2、定义run方法,run方法是线程执行函数
    import os,time
    from threading import Thread
    class MyThread(Thread):
    def run(self):
    print('start son thread')
    time.sleep(1)
    print('end son thread',os.getpid())
    for i in range(3):
    MyThread().start()
    ------------------结果:
    start son thread
    start son thread
    start son thread
    end son thread 6116
    end son thread 6116
    end son thread 6116
    [2]面向对象启动线程并往线程函数里传参
    #1、创建init方法,传参进入类中 2、执行父类的init方法,不执行报错入下
    import os,time
    from threading import Thread
    class MyThread(Thread):
    def init(self,name):
    super().init() #执行父类init方法在实例变量后面报错了,不知道怎么回事,有时间测试一下
    self.name=name

    def run(self):
        time.sleep(1)
        print('end son thread',os.getpid(),self.name)

    for i in range(3):
    MyThread("mcw").start()
    ------------------结果:
    end son thread 2060 mcw
    end son thread 2060 mcw
    end son thread 2060 mcw

    不执行父类init报错:
    assert self._initialized, "Thread.init() not called"
    AssertionError: Thread.init() not called

    [3]start执行的原理
    class Foo:
    def start(self):
    self.run()
    def run(self):
    print('run in Foo')
    class Son(Foo):
    def run(self):
    print('run in son')
    Son().start()
    ---------------结果:
    run in son
    [4]自定义类中把init方法去掉后,实例化的时候还带有传参报错
    t=MyThread("mcw")
    File "C:python3libthreading.py", line 780, in init
    assert group is None, "group argument must be None for now"
    AssertionError: group argument must be None for now

    7)线程里面的其它方法 查看线程id

    [1]用类来启动线程,类里面和外面查看线程的id。对象.ident self.ident。注意:在init里定义与父类相同的实例变量名,会被覆盖掉的。
    import os,time
    from threading import Thread
    class MyThread(Thread):
    def run(self):
    time.sleep(1)
    print(' thread id',self.ident)
    for i in range(3):
    t=MyThread()
    t.start()
    print("线程id",t.ident)
    [2]current_thread()在哪个线程里代表哪个线程。用函数来启动线程,查看线程id 。
    #当前线程current_thread()对象,记得加括号(),函数中调用对象
    import time
    from threading import current_thread,Thread
    def func(i):
    print('start son thread',i,current_thread(),type(current_thread()))
    print("线程函数中调用执行这个函数的线程对象的线程id:%s"%current_thread().ident)
    time.sleep(1)
    print('end son thread',)
    t=Thread(target=func,args=(1,))
    t.start()
    print("main",t,t.ident)
    --------------结果:
    start son thread 1 <Thread(Thread-1, started 4444)> <class 'threading.Thread'>
    线程函数中调用执行这个函数的线程对象的线程id:4444
    main <Thread(Thread-1, started 4444)> 4444
    end son thread

    from threading import current_thread,Thread
    def func():
    print('end son thread',current_thread().ident)
    t=Thread(target=func).start()
    print("main thread",current_thread().ident)
    ------------结果:
    end son thread 1936 #current_thread()在哪个线程里代表哪个线程
    main thread 4928
    [3]enumerate active_count
    from threading import current_thread,Thread,active_count,enumerate
    def func():
    print('end son thread',current_thread().ident)
    t=Thread(target=func).start()
    print(enumerate(),enumerate) #主线程和子线程两个。enumerate()表示当前运行的线程,
    print(active_count(),active_count) #active_count()代表当前运行的线程的个数,相当于len(enumerate())
    -------------------结果:
    end son thread 4324
    2
    [<_MainThread(MainThread, started 2460)>, <Thread(Thread-1, started 4324)>] <function enumerate at 0x006E1270>
    2 <function active_count at 0x006E11E0>
    [4]terminate 能结束进程 。
    在线程中不能从主线程结束一个子线程

    8)进程和线程的开启效率差。进程一般开cpu个数的1到2倍,开多了浪费系统资源

    import time
    from threading import Thread
    from multiprocessing import Process
    def func(a,b):
    c=a+b
    if name=="main":
    p_start=time.time()
    p_li=[]
    for i in range(100):
    p=Process(target=func,args=(i,i2))
    p.start()
    p_li.append(p)
    for p in p_li:p.join()
    print("进程:",time.time()-p_start)
    t_start=time.time()
    t_li = []
    for i in range(100):
    t=Thread(target=func,args=(i,i
    2))
    t.start()
    t_li.append(t)
    for t in t_li:t.join()
    print("线程:",time.time() - t_start)
    ----------------结果:
    进程: 6.1583521366119385
    线程: 0.01500082015991211 #几百倍速度差距

    9)线程共享进程中的数据。子线程在进程中共享数据,

    from threading import Thread
    n=100
    def func():
    global n #最好不要轻易修改全局变量
    n-=1
    t_li=[]
    for i in range(100):
    t=Thread(target=func)
    t_li.append(t)
    t.start()
    for t in t_li:t.join()
    print(n)
    -----------结果:
    0

    10)守护线程

    [1]没有守护线程的时候
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.start()
    ---------结果:
    一直打印“in son1”
    [2]有守护线程的时候,线程开启后,后面没有运行一段时间的代码
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    ---------------结果:
    什么都没有打印
    #这说明后面没代码了,主线程结束守护线程就结束了
    [3]有守护线程的时候,线程开启后,后面有运行一段时间的代码time.sleep(3)
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    time.sleep(3)
    ----------结果:
    打印5次"in son1"后结束
    #这说明后面还有代码,主线程执行完代码结束后守护线程就结束了
    [4]
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    time.sleep(3.1)
    ---------结果:
    打印6次"in son1"后结束
    #和上面打印5次对比,5次是因为主线程执行的3秒内,守护线程一直在运行,守护线程0.5秒打印一次,3秒到了主线程结束守护线程3秒也就结束。守护线程每0.5秒后打印一次,3秒后因为主线程停止守护线程也停止所以没有打印第6次
    #这里将主线程运行时间+0.1,也就是主线线程运行时间大于3秒,那么守护线程也运行3秒以上,刚过3秒就运行到打印“in son1”,所以打印6次
    [5]
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    def son2():
    for i in range(5):
    time.sleep(1)
    print("in son2")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    Thread(target=son2).start()
    time.sleep(3)
    -----------结果:
    in son1
    in son2
    in son1
    .......
    "in son2"打印5次,"in son1"打印9次
    #这说明守护线程一直等到所有的线程都结束之后才结束的
    #这说明守护线程除了守护主线程的代码之外也会守护子线程
    #主线程代码执行完毕,主线程没有关闭。主线程等待所有子线程结束之后才结束。守护线程守护主线程,所以守护线程也要等所有子线程结束之后才结束。如果子线程都结束了,主线程还有程序在运行,那么守护线程还是在守护主线程。
    [6]
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    time.sleep(3)
    print('1')
    print('1')
    print('1')
    ----------结果:
    六次 “in son1”
    1
    1
    1
    #原因:为什么主线程有代码在运行的时候,守护线程没有做打印操作了呢,因为这里守护线程是0.5s打印一次,主线程打印3次“1”所花费的时间不足0.5s不够守护线程到达下一次打印的时间。为什么打印6次呢,因为主线程sleep3秒正好达到守护线程打印第6次的时间,在主线程第3秒到打印出第一个“1”这个时间之间,守护线程才打印出第6个“in son1”。time.sleep(3)后面没有代码,守护线程在第3秒是没有执行到打印就随着主线程停止而停止了的。
    [7]
    import time
    from threading import Thread
    def son1():
    while True:
    time.sleep(0.5)
    print("in son1")
    t=Thread(target=son1)
    t.daemon=True
    t.start()
    time.sleep(3)
    print('1')
    time.sleep(1)
    print('1')
    ---------------结果:
    六个“in son1” 然后:
    1
    in son1
    in son1
    1

    11)在多进程里启动多线程

    import os
    from multiprocessing import Process
    from threading import Thread

    def tfunc():
    print('tfunc线程',os.getpid())
    def pfunc():
    print('pfunc进程-->',os.getpid())
    Thread(target=tfunc).start()

    if name == 'main':
    Process(target=pfunc).start()
    ------------------结果:
    pfunc进程--> 9716
    tfunc线程 9716

    方法总结:
    开启进程执行进程函数
    进程函数里开启线程执行线程函数
    线程函数里执行线程运行的程序

  • 相关阅读:
    python_request中params和data
    python_多线程加锁
    python_多线程join和setDaemon
    python_faker模块
    python_jsonpath模块
    MyBatis-自定义结果映射规则
    MyBatis-SELECT基本查询
    MyBatis-参数处理
    MyBatis-mybatis全局映射文件解析
    MySQL高级-主从复制
  • 原文地址:https://www.cnblogs.com/machangwei-8/p/10908000.html
Copyright © 2011-2022 走看看