pytnon—线程,进程

一、what线程,what进程

  1、进程

    是资源的整合。一个程序对于操作系统来说就是一个进程、例如打开浏览器、打开word等都是打开一个进程。

  2、线程

  是程序里面的最小执行单元。帮助进程干活的,线程之间相互独立

    多线程多用于处理IO密集型任务频繁写入读出,cpu负责调度,消耗的是磁盘空间

  3、线程是包含在一个进程里面的,一个进程可以有多个线程

  4、一个进程里面默认有一个线程

  5、主线程与子线程,一个程序默认有一个主线程,由主线程来启动子线程

 

导入模块

import threading

传统方式(单线程)

串行

def down_load():
    time.sleep(5)
    print('运行完成')
    
for i in range(3):
    down_load()

多线程方式

 并行

for i in range(3):
    t=threading.Thread(target=down_load)            #实例化一个线程
    t.start()                                       #开始运行

 

  down_load不要带(),不然属于自己调用了

线程之间相互独立
t1=time.time()
for i in range(3):
    t=threading.Thread(target=down_load)            #实例化一个线程
    t.start()                                       #开始运行

print('运行时间',time.time()-t1)

  上面的代码,总共有4个线程,循环里面启动了3个线程,还有一个主线程在运行所以结果如下

主线程运行结束打印运行时间,后等待子线程结束

运行时间 0.0009999275207519531
运行完成
运行完成
运行完成

 

查看当前线程数线程

print(threading.active_count())                 #查看    线程数
print(threading.current_thread())               #查看  当前线程
主线程等待子线程结束(并行)
def down_load():
    time.sleep(5)
    print('运行完成')


# 多线程
t1=time.time()
for i in range(3):
    t=threading.Thread(target=down_load)
    t.start()
    # t.join()                                      #这里是树形结构不是并行结构
# t.join()                                          #这里等待的是最后一个线程结束的时间

while threading.activeCount()!=1:                  #主线程等待子线程结束
    pass

 

多线程下载图片

 

import requests,threading,time
from hashlib import md5
def down_load_pic(url):
    req=requests.get(url)
    m=md5(url.encode())
    with open(m.hexdigest()+'.png','wb') as fw:
        fw.write(req.content)

url_list=['http://url.cn/Tfhpen?.jpg',
          'http://www.nnzhp.cn/wp-content/uploads/2019/11/542824dde1dbd29ec61ad5ea867ef245.png'\
          'http://www.nnzhp.cn/wp-content/uploads/2019/10/5901238e6ec4a53bfd17e68762c3403a.png',\
          'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png']

t1=time.time()
for url in url_list:
    t= threading.Thread(target=down_load_pic,args=(url,))
    t.start()
while threading.activeCount()!=1:
    pass
#并行下载时间哪个最长,就是哪个时间
print('运行时间:',time.time()-t1)

 守护线程

import yagmail,threading
def send_mail():
    smtp=yagmail.SMTP(host='smtp.126.com',
                 user='newcwl@126.com',
                 password='KVXLMGVQZUZPPZBK'

    )
    smtp.send(to='526962645@qq.com',cc=[],subject='测试python邮箱发送内容',
              contents='正文是:"hahahahahhahahaha"',attachments=[])

# 如果由于网络或者其他原因导致发送缓慢,而主线程没有等待执行完毕
def async_send_mail():
    t=threading.Thread(target=send_mail)
    t.start()
# 这里专门启动了一个线程来发邮件
# 不用等着了

线程池(根据指定的线程池大小自动分发数据)(数据量大的时候应用)

import requests,threadpool
from hashlib import md5

def down_load_pic(url):
    req=requests.get(url)
    m=md5(url.encode())
    with open(m.hexdigest()+'.png','wb') as fw:
        fw.write(req.content)

url_list=['http://www.nnzhp.cn/wp-content/uploads/2019/07/mysql.jpeg',\
          'http://url.cn/Tfhpen?.jpg',\
          'http://www.nnzhp.cn/wp-content/uploads/2019/03/js.png',\
          'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png']


pool=threadpool.ThreadPool(8)                       #实例化线程池(指定大小)
reqs=threadpool.makeRequests(down_load_pic,url_list)#分配数据(第一个参数是函数,第二个参数是数据)
[pool.putRequest(req) for req in reqs]
pool.wait()             #等待
print('end')

 守护线程(陪葬的)

只要主线程结束,守护线程立即结束,不管子线程有没有结束

import threading,time
def down_load():
    time.sleep(4)
    print('运行结束')
for i in range(10):
    t=threading.Thread(target=down_load)
    t.setDaemon(True)           #设置子线程为守护线程
    t.start()

print('over')

 获取线程返回值

import requests,threading,time,threadpool
from hashlib import md5
result={}
def down_load_pic(url):
    req=requests.get(url)
    m=md5(url.encode())
    file_name=m.hexdigest()+'.png'
    with open(file_name,'wb') as fw:
        fw.write(req.content)
    result[file_name]=threading.current_thread()        #获取线程返回值
    return result

url_list=['http://www.nnzhp.cn/wp-content/uploads/2019/07/mysql.jpeg',\
          'http://url.cn/Tfhpen?.jpg',\
          'http://www.nnzhp.cn/wp-content/uploads/2019/03/js.png',\
          'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png']

t1=time.time()
for url in url_list:
    t= threading.Thread(target=down_load_pic,args=(url,))
    t.start()
while threading.activeCount()!=1:
    pass
#并行下载时间哪个最长,就是哪个时间
print('运行时间:',time.time()-t1)
print(result)

 锁

 线程锁,线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据。

 

import threading
num=0
lock=threading.Lock()

def add():
    global num
    # lock.acquire()      #加锁
    # num+=1
    # lock.release()          #解锁     (如果不解锁,就会产生死锁程序运行到这无法执行)
    
    with lock:          #简写,同注释部分一样
        num+=1

for i in range(20):
    t=threading.Thread(target=add,)
    t.start()
while threading.activeCount()!=1:
    pass
print(num)

多进程

 

import multiprocessing,time

def down_load():
    time.sleep(5)
    print('运行完了')

if __name__ == '__main__':#必须加这个才能启动多进程


    for i in range(5):
        p = multiprocessing.Process(target=down_load)
        p.start()

    while len(multiprocessing.active_children())!=0:#等待子进程结束
        pass
    # print(multiprocessing.active_children())    #
    print(multiprocessing.current_process())
    print('end')

 

 

 

1、如果是CPU密集型代码(循环、计算等),由于计算工作量多和大,计算很快就会达到100,然后触发GIL的释放与在竞争,多个线程来回切换损耗资源,所以在多线程遇到CPU密集型代码时,单线程会比较快;

   算法,计算、数据分析,等不和磁盘打交道的

 

2、如果是I\O密集型代码(文件处理、网络爬虫),开启多线程实际上是并发(不是并行),IO操作会进行IO等待,线程A等待时,自动切换到线程B,这样就提升了效率。

   磁盘io、网络io、input、output

 

 

 
posted @ 2020-04-12 08:15  localhost;  阅读(225)  评论(0编辑  收藏  举报