莫烦Python笔记__Python多线程技巧

1.threading的四种基本操作

  a.查看已激活线程

  b.查看所有线程信息

  c.查看正在运行的线程信息

  d.添加线程

 

import threading
"""
。 介绍threading的基本功能;
。 添加线程操作;
"""
#查看已激活现成
print(threading.active_count())

#查看所有现成信息
print(threading.enumerate())

#查看正在运行的线程信息
print(threading.current_thread())

#添加线程
def thread_job():
    print("This is a added thread, number is %s"%(threading.current_thread))

def main():
    added_thread = threading.Thread(target=thread_job,name="Luna")
    added_thread.start()
    print(threading.active_count())
    print(threading.enumerate())

if __name__ == '__main__':
    main()

 显示结果:

1
[<_MainThread(MainThread, started 2236)>]
<_MainThread(MainThread, started 2236)>
This is a added thread, number is <function current_thread at 0x000001CE6B067400>
2
[<_MainThread(MainThread, started 2236)>]
[Finished in 0.5s]

  

2.threading的join()操作__join:将被join的线程加入主线程

  a.没有join操作

import threading
import time

"""
join函数:可以让join()的现成先完成后在进行后续的工作
"""

def thread_job1():
    print("T1 started...\n")
    print(threading.current_thread)
    for i in range(10):
        time.sleep(0.1)
    print("T1 finished...\n")

def thread_job2():
    print("T2 started...\n")
    print(threading.current_thread)
    print("T2 finished ...\n")

def main():
    added_thread1 = threading.Thread(target=thread_job1,name='T1')
    added_thread2 = threading.Thread(target=thread_job2,name='T2')

    added_thread1.start()
    added_thread2.start()

    #必须在add_thread1.join完成后才可执行后面的
    #可屏蔽测试没有join功能时的情况
    # added_thread1.join(timeout=None)
    # added_thread2.join(timeout=None)

    print(threading.enumerate())
    print("目前总线程数量:{}".format(str(threading.active_count)))

    print("All done")

if __name__ == '__main__':
    main()

  结果:

T1 started...

<function current_thread at 0x000001B569FA7378>
T2 started...

[<_MainThread(MainThread, started 14804)>, <Thread(T1, started 1248)>, <Thread(T2, started 14528)>]
目前总线程数量:<function active_count at 0x000001B569FA8510>
<function current_thread at 0x000001B569FA7378>
All done
T2 finished ...

T1 finished...

  可以看出:先进行T1>>T2>>主线程>>T2先完成>>T1先完成

  b.进行join()操作

import threading
import time

"""
join函数:可以让join()的现成先完成后在进行后续的工作
"""

def thread_job1():
    print("T1 started...\n")
    print(threading.current_thread)
    for i in range(10):
        time.sleep(0.1)
    print("T1 finished...\n")

def thread_job2():
    print("T2 started...\n")
    print(threading.current_thread)
    print("T2 finished ...\n")

def main():
    added_thread1 = threading.Thread(target=thread_job1,name='T1')
    added_thread2 = threading.Thread(target=thread_job2,name='T2')

    added_thread1.start()
    added_thread2.start()

    #必须在add_thread1.join完成后才可执行后面的
    #可屏蔽测试没有join功能时的情况
    added_thread1.join(timeout=None)
    added_thread2.join(timeout=None)

    print(threading.enumerate())
    print("目前总线程数量:{}".format(str(threading.active_count)))

    print("All done")

if __name__ == '__main__':
    main()

  结果

T1 started...

<function current_thread at 0x000002CF02FE7400>
T2 started...

<function current_thread at 0x000002CF02FE7400>
T2 finished ...

T1 finished...

[<_MainThread(MainThread, started 8204)>]
目前总线程数量:<function active_count at 0x000002CF02FE8598>
All done
[Finished in 1.2s]

  可看出 先完成T2(没有延迟)>>T1>>最后ALL DONE

 

3.Queue来进行存储(线程不能return,只能q.put(), 主程序中q.get())

  以前的线程都是没有返回值的

import threading
import time
from queue import Queue
import numpy as np

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

#定义一个被多线程调用的任务
def thread_job(l,q):
    for i in range(len(l)):
        l[i] = l[i]**2
    #注:多线程调用的函数不能用return返回值
    q.put(l) 

def multithreading():
    #q中存放返回值,用来代替return
    q = Queue() 
    threads = []
    # data = np.array([[1,2,3],[2,3,4],[3,3,3],[4,5,6]])
    # data.tolist()
    data = [[1,2,3],[2,3,4],[3,3,3],[4,5,6]]
    #results用来保存结果
    results = []

    #定义四个线程
    #每个线程分别算data列表中的一个子列表
    for i in range(4):
        t = threading.Thread(target=thread_job,args=(data[i],q))
        t.start()
        threads.append(t)

    #分别join四个线程到主线程
    for thread in threads:
        thread.join()

    #results保存结果
    for _ in range(4):
        #q.get()获取结果
        results.append(q.get())

    print(results)

if __name__ == '__main__':
    multithreading()

   结果:

[[1, 4, 9], [4, 9, 16], [9, 9, 9], [16, 25, 36]]
[Finished in 0.3s]

 

 P.S 线程其实并不能真正的加速计算过程____GIL机制

线面的程序用来具体测试加入线程和不加入线程的程序运行时间 

GIL机制:

Global Interpreter Lock(GIL)
这个东西让 Python 还是一次性只能处理一个东西.
尽管Python完全支持多线程编程, 但是解释器的C语言实现部分在完全并行执行时并不是线程安全的。 实际上,解释器被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。 GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势 (比如一个使用了多个线程的计算密集型程序只会在一个单CPU上面运行)。

在讨论普通的GIL之前,有一点要强调的是GIL只会影响到那些严重依赖CPU的程序(比如计算型的。 如果你的程序大部分只会涉及到I/O,比如网络交互,那么使用多线程就很合适, 因为它们大部分时间都在等待。实际上,你完全可以放心的创建几千个Python线程, 现代操作系统运行这么多线程没有任何压力,没啥可担心的(不适用于CPU密集型计算)

多线程与多进程:

python多线程适合io操作密集型的任务(如socket server 网络并发这一类的)
python多线程不适合cpu密集操作型的任务,主要使用cpu来计算,如大量的数学计算。
那么如果有cpu密集型的任务怎么办,可以通过多进程来操作(不是多线程)。
假如CPU有8核,每核CPU都可以用1个进程,每个进程可以用1个线程来进行计算。

多进程适合在CPU 密集型操作(cpu 操作指令比较多,如科学计算,位数多的浮点运算)

多线程适合在IO 密集型操作(读写数据操作较多的,比如爬虫)

进程与线程的区别:

 

线程是并发,进程是并行;进程之间相互独立,是系统分配资源的最小单位,同一个进程中的所有线程共享资源。

 

进程:一个运行的程序或代码就是一个进程,一个没有运行的代码叫程序。

进程是系统进行资源分配的最小单位,进程拥有自己的内存空间,所以进程间数据不共享,开销大。

 

线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程的存在而存在,一个进程至少有一个线程,叫主线程,多个线程共享内存(数据共享和全局变量),因此提升程序的运行效率。

 

协程:用户态的轻量级线程,调度有用户控制,拥有自己的寄存器上下文和栈,切换基本没有内核切换的开销,切换灵活。

 

 

  
 1 # 我们创建一个 job, 分别用 threading 和 一般的方式执行这段程序. 
 2 # 并且创建一个 list 来存放我们要处理的数据. 在 Normal 的时候,
 3 # 我们这个 list 扩展4倍,在 threading 的时候, 我们建立4个线程, 
 4 # 并对运行时间进行对比.
 5 
 6 import threading
 7 from queue import Queue
 8 import copy
 9 import time
10 
11 def job(l, q):
12     res = sum(l)
13     q.put(res)
14 
15 def multithreading(l):
16     q = Queue()
17     threads = []
18     for i in range(4):
19         t = threading.Thread(target=job, args=(copy.copy(l), q), name='T%i' % i)
20         t.start()
21         threads.append(t)
22     [t.join() for t in threads]
23     total = 0
24     for _ in range(4):
25         total += q.get()
26     print(total)
27 
28 def normal(l):
29     total = sum(l)
30     print(total)
31 
32 if __name__ == '__main__':
33     l = list(range(1000000))
34     s_t = time.time()
35     normal(l*4)
36     print('normal: ',time.time()-s_t)
37     s_t = time.time()
38     multithreading(l)
39     print('multithreading: ', time.time()-s_t)
View Code

 

 

 5.Lock功能,锁住某线程,使其进行完之后才进行下一个线程

#进程锁
#先运行一个线程,在运行另一个线程
import threading
import time
from queue import Queue

#没有线程锁
def job1_withoutlock():
    global A
    for i in range(10):
        A += 1
        print('job1:',A)

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

#有线程锁
def job3_withlock():
    global B,lock 
    lock.acquire()
    for i in range(10):
        B+=1
        print(B)
    lock.release()

def job4_withlock():
    global B,lock
    lock.acquire()
    for i in range(10):
        B+=10
        print(B)
    lock.release()

if __name__ == '__main__':
    #全局变量A
    A = 0
    B = 0
    lock = threading.Lock()
    print("没有lock锁...\n")
    lock_without1 = threading.Thread(target=job1_withoutlock,name='withoutlock1')
    lock_without2 = threading.Thread(target=job2_withoutlock,name='withoutlock2')

    lock_without1.start()
    lock_without2.start()
    lock_without1.join()
    lock_without2.join()

    print("有lock锁...\n")
    lock_with1 = threading.Thread(target=job3_withlock,name='withlock3')
    lock_with2 = threading.Thread(target=job4_withlock,name='withlock4')

    lock_with1.start()
    lock_with2.start()
    lock_with1.join()
    lock_with2.join()
没有Lock:
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:
job1 1
job1 2
job1 3
job1 4
job1 5
job1 6
job1 7
job1 8
job1 9
job1 10
job2 20
job2 30
job2 40
job2 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110

  

 

 

转载于:https://www.cnblogs.com/IrivingLoveLuna/p/10282661.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值