• Python 多线程


    参考自:https://morvanzhou.github.io/tutorials/python-basic/basic/

    多线程模块的一些基本操作:

    首先导入模块:

    import threading

    获得已激活的线程数:

    threading.active_count()

    查看所有线程信息:

    threading.enumerate()

    输出的结果是一个<_MainThread(...)>带多个<Thread(...)>

    添加线程,threading.Thread()接收参数target代表这个线程要完成的任务,需要自行定义,name可以给线程定义名字

    def thread_job():
        print('This is a thread of %s' % threading.current_thread())
    
    def main():
        thread = threading.Thread(target=thread_job,name = 'T1')   # 定义线程 
        thread.start()  # 让线程开始工作
        
    if __name__ == '__main__':
        main()

    join()功能

           主要是为了让多线程按一个既定的顺序的执行。

    不加 join() 的结果

    我们让 T1 线程工作的耗时增加:

    import threading
    import time
    
    def thread_job():
        print("T1 start
    ")
        for i in range(10):
            time.sleep(0.1) # 任务间隔0.1s
        print("T1 finish
    ")
    
    added_thread = threading.Thread(target=thread_job, name='T1')
    added_thread.start()
    print("all done
    ")

    预想中输出的结果是否为:

    T1 start
    T1 finish
    all done

    但实际却是:

    T1 start
    all done
    T1 finish

    加入 join() 的结果 

    def T1_job():
        print("T1 start
    ")
        for i in range(10):
            time.sleep(0.1)
        print("T1 finish
    ")
    
    def T2_job():
        print("T2 start
    ")
        print("T2 finish
    ")
    
    thread_1 = threading.Thread(target=T1_job, name='T1')
    thread_2 = threading.Thread(target=T2_job, name='T2')
    thread_1.start() # 开启T1
    thread_2.start() # 开启T2
    thread_2.join()
    thread_1,join()
    print("all done
    ")
    T1 start
    T2 start
    T2 finish
    T1 finish
    all done

    储存进程结果 Queue

    代码实现功能,将数据列表中的数据传入,使用四个线程处理,将结果保存在Queue中,线程执行完后,从Queue中获取存储的结果.

    导入线程,队列的标准模块

    import threading
    import time
    from queue import Queue

    定义一个被多线程调用的函数

    函数的参数是一个列表l和一个队列q,函数的功能是,对列表的每个元素进行平方计算,将结果保存在队列中

    def job(l,q):
        for i in range (len(l)):
            l[i] = l[i]**2
        q.put(l)   #多线程调用的函数不能用return返回值

    定义一个多线程函数

    在多线程函数中定义一个Queue,用来保存返回值,代替return,定义一个多线程列表,初始化一个多维数据列表,用来处理:

    def multithreading():
        q =Queue()    #q中存放返回值,代替return的返回值
        threads = []
        data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]

    在多线程函数中定义四个线程,启动线程,将每个线程添加到多线程的列表中

    for i in range(4):   #定义四个线程
        t = threading.Thread(target=job,args=(data[i],q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面
        t.start()#开始线程
        threads.append(t) #把每个线程append到线程列表中

    分别join四个线程到主线程

    for thread in threads:
        thread.join()

    定义一个空的列表results,将四个线程运行后保存在队列中的结果返回给空列表results

    results = []
    for _ in range(4):
        results.append(q.get())  #q.get()按顺序从q中拿出一个值
    print(results)

    完整的代码

    import threading
    import time
    
    from queue import Queue
    
    def job(l,q):
        for i in range (len(l)):
            l[i] = l[i]**2
        q.put(l)
    
    def multithreading():
        q =Queue()
        threads = []
        data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]
        for i in range(4):
            t = threading.Thread(target=job,args=(data[i],q)) #参数列表 args
            t.start()
            threads.append(t)
        for thread in threads:
            thread.join()
        results = []
        for _ in range(4):
            results.append(q.get())
        print(results)
    
    if __name___=='__main__':
        multithreading()

    最后运行结果为:

    [[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]]


    线程锁 Lock

    不使用 Lock 的情况

    函数一:全局变量A的值每次加1,循环10次,并打印

    def job1():
        global A
        for i in range(10):
            A+=1
            print('job1',A)

    函数二:全局变量A的值每次加10,循环10次,并打印

    def job2():
        global A
        for i in range(10):
            A+=10
            print('job2',A)

    主函数:定义两个线程,分别执行函数一和函数二

    if __name__== '__main__':
        A=0
        t1=threading.Thread(target=job1)
        t2=threading.Thread(target=job2)
        t1.start()
        t2.start()
        t1.join()
        t2.join()

    完整代码:

    import threading
    
    def job1():
        global A
        for i in range(10):
            A+=1
            print('job1',A)
    
    def job2():
        global A
        for i in range(10):
            A+=10
            print('job2',A)
    
    if __name__== '__main__':
        lock=threading.Lock()
        A=0
        t1=threading.Thread(target=job1)
        t2=threading.Thread(target=job2)
        t1.start()
        t2.start()
        t1.join()
        t2.join()

    运行结果

    job1job2 11
    job2 21
    job2 31
    job2 41
    job2 51
    job2 61
    job2 71
    job2 81
    job2 91
    job2 101
     1
    job1 102
    job1 103
    job1 104
    job1 105
    job1 106
    job1 107
    job1 108
    job1 109
    job1 110

    可以看出,打印的结果非常混乱

    使用 Lock 的情况 

    lock在不同线程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。

    函数一和函数二加锁

    def job1():
        global A,lock
        lock.acquire()
        for i in range(10):
            A+=1
            print('job1',A)
        lock.release()
    
    def job2():
        global A,lock
        lock.acquire()
        for i in range(10):
            A+=10
            print('job2',A)
        lock.release()

    主函数中定义一个Lock

    if __name__== '__main__':
        lock=threading.Lock()
        A=0
        t1=threading.Thread(target=job1)
        t2=threading.Thread(target=job2)
        t1.start()
        t2.start()
        t1.join()
        t2.join()

    完整的代码

    import threading
    
    def job1():
        global A,lock
        lock.acquire()
        for i in range(10):
            A+=1
            print('job1',A)
        lock.release()
    
    def job2():
        global A,lock
        lock.acquire()
        for i in range(10):
            A+=10
            print('job2',A)
        lock.release()
    
    if __name__== '__main__':
        lock=threading.Lock()
        A=0
        t1=threading.Thread(target=job1)
        t2=threading.Thread(target=job2)
        t1.start()
        t2.start()
        t1.join()
        t2.join()

    运行结果

    从打印结果来看,使用lock后,一个一个线程执行完。使用lock和不使用lock,最后打印输出的结果是不同的。

  • 相关阅读:
    linux随记
    springboot-2
    netty-lean1
    nginx
    自定义启动器
    arrayList add
    Mybatis 转义符
    idea 闪退 但是启动的服务还在解决办法
    java 通过map根据list某个字段进行合并
    java list的深拷贝
  • 原文地址:https://www.cnblogs.com/PrayG/p/10853198.html
Copyright © 2020-2023  润新知