zoukankan      html  css  js  c++  java
  • python使用笔记26--多线程、多进程

    1、概念

    线程、进程
    进程是资源的集合,也就是一个程序
    线程是一个程序运行的最小单位
    线程是在进程里面的
    默认,一个进程就只有一个线程

    一个电脑有几核CPU就只能同时运行几个任务,比如4核CPU只能同时运行4个线程

    我们在操作电脑时,感觉是同时运行多个任务,是因为CPU的运算速度很快,有上下文切换,我们感觉不到

    python里的多线程利用不了多核CPU,比如我的电脑是8核的CPU,起100个线程,这100个线程都是在一个CPU里面执行,其他7个CPU是空闲的

    因为线程之间数据是共享的,同时来处理数据会乱,GLI全局解释器锁,保证线程都在同一个CPU上运行

    多进程可以利用多核CPU

      CPU密集型任务,用多进程-->消耗CPU比较多

      IO(磁盘IO,网络IO)密集型任务,用多线程-->消耗IO比较多

    #1、多线程,线程之间数据是共享的

    #2、多进程,进程之间数据是独立的

    #3、协程,一个线程,速度很快,从头到尾都只有一个线程,利用的原理是异步IO

      Nginx   -->一个线程

    2、多线程

    2.1、多线程代码

    串行的方式是执行完一个,再接着执行第二个

    多线程是同时启用多个线程去操作

     1 def insert_db():
     2     time.sleep(3)
     3     print('insert_db over')
     4 
     5 start_time = time.time()
     6 for i in range(3): #串行的方式
     7     insert_db()
     8 end_time = time.time()
     9 print('串行的执行的时间',end_time - start_time )
    10 
    11 start_time2 = time.time()
    12 #2、判断当前存活的线程个数为1个时
    13 for i in range(3):
    14     t = threading.Thread(target=insert_db)
    15     t.start()
    16 
    17 while threading.activeCount()!=1:
    18     pass
    19 
    20 end_time2 = time.time()
    21 print('多线程执行的时间',end_time2 - start_time2)#只是主线程执行的时间,不计算子线程执行的时间

    执行结果如图所示:

    2.2、多线程的时间统计

     1 def insert_db():
     2     time.sleep(3)
     3     print('insert_db over')
     4 start_time2 = time.time()
     5 #2、判断当前存活的线程个数为1个时
     6 for i in range(3):
     7     t = threading.Thread(target=insert_db)
     8     t.start()
     9 
    10 end_time2 = time.time()
    11 print('多线程执行的时间',end_time2 - start_time2)#只是主线程执行的时间,不计算子线程执行的时间

    执行结果如图所示:

     正常执行应该是3秒多一点,这里是因为只是主线程执行的时间,没有计算子线程执行的时间,如何解决该问题?

    1.用两次循环来解决,这样代码看起来比较繁琐

     1 threads = []
     2 start_time2 = time.time()
     3 #2、判断当前存活的线程个数为1个时
     4 for i in range(3):
     5     t = threading.Thread(target=insert_db)
     6     t.start()
     7     threads.append(t)
     8 
     9 for i in threads:
    10     i.join()
    11 end_time2 = time.time()
    12 print('多线程执行的时间',end_time2 - start_time2)

    2.用while循环来解决,判断当前活动的线程数为1,统计时间,如果不为1,则进入循环,不统计时间

     1 start_time2 = time.time()
     2 #2、判断当前存活的线程个数为1个时
     3 for i in range(3):
     4     t = threading.Thread(target=insert_db)
     5     t.start()
     6 
     7 while threading.activeCount()!=1:
     8     pass
     9 
    10 end_time2 = time.time()
    11 print('多线程执行的时间',end_time2 - start_time2)

    2.3、多线程传参

     用元组的方式传参,args=(i,)#这里传入的是一个元组,一个参数时要加,

    也可以用数组的方式来传参,args=['lxy']

     1 import threading
     2 import requests
     3 import hashlib
     4 import time
     5 def down_load(url):
     6     name = hashlib.md5(url.encode()).hexdigest()
     7     r = requests.get(url)
     8     with open('%s.jpg'%name,'wb') as fw:
     9         fw.write(r.content)
    10 
    11 l = [
    12     'http://www.nnzhp.cn/wp-content/themes/QQ/images/logo.jpg',
    13     'http://www.nnzhp.cn/wp-content/uploads/2016/12/2016aj5kn45fjk5-150x150.jpg',
    14     'http://www.nnzhp.cn/wp-content/themes/QQ/images/thumbnail.png'
    15 ]
    16 
    17 for i in l:
    18     t = threading.Thread(target=down_load,args=(i,))#args=(i,),一个参数的时候要加,
    19     t.start()
    20 
    21 while threading.activeCount() != 1:
    22     pass
    23 
    24 print('down_load over...')

    2.4、多线程获取函数返回值

    多线程运行函数时,是没有办法获取到函数的返回值,所以可以定义一个全局的list,把函数的返回结果存到list就可以了

    1 case_result = []
    2 def run_case(case_name):
    3     print('run case over...')
    4     case_result.append({case_name,'success'})

    2.5、守护线程

    守护线程,一旦主线程死掉,不管守护线程有没有执行完成,守护线程全部都结束

     1 #守护线程,一旦主线程死掉,不管守护线程有没有执行完成,全部都结束
     2 
     3 import threading
     4 import time
     5 
     6 def talk(name):
     7     print('正在和%s聊天'%name)
     8     time.sleep(200)
     9 
    10 
    11 def shipin(name):
    12     print('正在和%s视频' % name)
    13     time.sleep(200)
    14 
    15 
    16 print('qq聊天窗口')
    17 t1 = threading.Thread(target=talk,args=['xxl'])
    18 t1.setDaemon(True)#设置线程为守护线程
    19 t1.start()
    20 
    21 
    22 t2 = threading.Thread(target=shipin,args=['lxy'])
    23 t2.setDaemon(True)#设置线程为守护线程
    24 t2.start()
    25 
    26 
    27 time.sleep(5)
    28 print('结束')

    2.6、线程锁

    多个线程同时操作同一个数据时,会有问题,这个时候需要用到线程锁

    线程锁需要设置锁定时长,数据操作完成后,需要解锁,不然其他线程会进入无线等待

     1 #线程锁
     2 #多个线程同时操作同一个数据的时候,会有问题
     3 import threading
     4 lock = threading.Lock()
     5 count = 0
     6 def test():
     7     global count
     8     lock.acquire(timeout=3000)#加锁,设置超时时间为3毫秒
     9     count += 1
    10     print(count)
    11     lock.release()#解锁
    12 
    13 for i in range(100):
    14     t = threading.Thread(target=test)
    15     t.start()

    3、多进程

     1 import multiprocessing
     2 import time
     3 import threading
     4 lock = multiprocessing.Lock()#
     5 a = 1
     6 
     7 def xxx():
     8     pass
     9 
    10 def test():
    11     for i in range(20):#进程里可以执行多个线程
    12         t = threading.Thread(target=xxx)
    13         t.start()
    14     time.sleep(6)
    15     global a
    16     with lock:#加锁,with用完之后会自动释放,因为with会自动管理上下文,进程里加锁没有啥意义
    17         a += 1
    18     print(a)#a的值为2
    19     print('over...')
    20 
    21 '''
    22 主进程叫醒进程,进程再开始干活
    23 进程是包含线程的
    24 '''
    25 if __name__ == '__main__':#multiprocessing要用main方法
    26     for i in range(5):#6个进程--6个线程
    27         p = multiprocessing.Process(target=test,name='ssz')#target:方法名,name:进程名,args:参数
    28         p.start()#进程启动后,加上主进程有两个进程在运行
    29         #print(p.pid)#进程ID
    30 
    31     while len(multiprocessing.active_children())!=0:#等待
    32         #print(multiprocessing.active_children())
    33         pass
    34     print('最后的over...')
    35     print(a)#a的值为1,是因为进程之间的数据是独立的
    36     #print('abc...')
  • 相关阅读:
    班会记录
    CSS之伪元素
    JavaScript之返回顶部
    尝试Hexo
    GitHub之上传文件
    Git之使用
    Git之基本命令
    运行第一个Node.js程序
    go语言圣经 map 章节习题
    go语言圣经第4章JSON部分习题
  • 原文地址:https://www.cnblogs.com/cjxxl1213/p/13121790.html
Copyright © 2011-2022 走看看