zoukankan      html  css  js  c++  java
  • 多线程、多进程

    多线程、多进程


    进程:一个进程就是一个程序。
    线程:线程就是进程里面最小的执行单元。
    线程是在进程里面的,干活的还是线程。
    一个进程里面最少有一个线程,可以有多个线程
    每个线程之间都是互相独立的
    没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。

    串行:

    1 import threading,time
    2 def run():
    3     time.sleep(5)
    4     print('哈哈哈哈')
    7 for i in range(5):#串行
    8     run()

    多线程

    复制代码
    1 import threading,time
    3 def run(name):
    4     time.sleep(5)
    5     print('【%s】哈哈哈哈'%name)
    6 for i in range(10):
    7     t=threading.Thread(target=run,args=(i,))#args传元组时,如果只有一个参数必须加一个逗号
    8     t.start()
    复制代码
    import threading
    import hashlib
    import requests
    
    def md5(msg):
        msg = str(msg)
        m = hashlib.md5(msg.encode())
        return m.hexdigest()
    
    def down_load_pic(url):
        print('图片下载开始',url)
        r = requests.get(url)
        file_name = md5(url)+'.png'
        with open(file_name, 'wb') as fw:
            fw.write(r.content)
            print('%s图片下载完成'%file_name)
    
    urls = ['https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140',
            'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140']
    for url in urls:
            t = threading.Thread(target=down_load_pic,args=[url])
            t.start()
    while threading.active_count()!=1:
        pass
    print('所有照片已下载完成!')

    获取不到返回值怎么办?return回来的返回值获取不到

    复制代码
    import threading,time
    all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
    def run(name):
        time.sleep(5)
        print('【%s】哈哈哈哈'%name)
        name ='hhj'+name
        all_res.append(name)
        print(all_res)
    for i in range(10):
        t=threading.Thread(target=run,args=(str(i),))#args要传元组,如果只有一个参数必须加一个逗号
        t.start()
    复制代码

    等待子线程都执行完成再计时和返回字典:

    方法1:

    复制代码
    import threading,time
    all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
    def run(name):
        time.sleep(5)
        print('【%s】哈哈哈哈'%name)
        name ='hhj'+name
        all_res.append(name)
    
    for i in range(10):
        t=threading.Thread(target=run,args=(str(i),))
        t.start()
    #主线程,线程之间是相互独立的
    while threading.active_count()!=1:#判断当前活动的线程是几个,如果是1的话,说明子线程已经执行完成了
        pass
    end = time.time()
    print(end-start)
    print('sleep之后的。。',all_res)
    复制代码

    还有一种方法:

    # t.join()#等待
    复制代码
     1 import threading,time
     2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
     3 def run(name):
     4     time.sleep(5)
     5     print('【%s】哈哈哈哈'%name)
     6     name ='hhj'+name
     7     all_res.append(name)
     8 
     9 for i in range(10):
    10     t=threading.Thread(target=run,args=(str(i),))
    11     threads.append(t)
    12     t.start()
    13 for t in threads:#再统一去等待子线程执行结束
    14     t.join()#等待
    15 end = time.time()
    16 print(end-start)
    17 print('sleep之后的。。',all_res)

    复制代码

    查看线程的id

    复制代码
     1 import threading,time
     2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
     3 def run(name):
     4     print('子线程执行的。。',threading.current_thread())
     5     time.sleep(5)
     6     print('【%s】哈哈哈哈'%name)
     7     name ='hhj'+name
     8     all_res.append(name)
     9 
    10 for i in range(3):
    11     t=threading.Thread(target=run,args=(str(i),))
    12     threads.append(t)
    13     t.start()
    14 for t in threads:#再统一去等待子线程执行结束
    15     t.join()#等待
    16 
    17 print('主线程执行的。。', threading.current_thread())
    18 
    19 end = time.time()
    20 print(end-start)
    21 print('sleep之后的。。',all_res)
    复制代码

     

    守护线程:

    复制代码
     1 #守护线程
     2 #守护线程就是和秦始皇陪葬的人一样
     3 #主线程就是秦始皇
     4 #子线程就是陪葬的人
     5 import threading
     6 import time
     7 def run():
     8     time.sleep(9)
     9     print('run...')
    10 for i in range(10):
    11     t = threading.Thread(target=run)
    12     t.setDaemon(True)#设置子线程成为一个守护线程
    13     t.start()
    14 print('over.')
    复制代码

    注释掉守护线程:

    复制代码
     1 import threading
     2 import time
     3 def run():
     4     time.sleep(9)
     5     print('run...')
     6 for i in range(10):
     7     t = threading.Thread(target=run)
     8     # t.setDaemon(True)#设置子线程成为一个守护线程
     9     t.start()
    10 print('over.')
    复制代码

    没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。

    python里面的多线程,是利用不了多核cpu的,只能利用一个核心的cpu

    有些情况下,你用多线程的时候会发现它比单线程速度还慢。

     查看电脑的cpu是几核的:

    锁:

    import threading
    count = 0
    lock = threading.Lock()
    
    def add():
        global count
        for i in range(1000000):
        #法1
            # lock.acquire()#加锁,线程安全;多线程的时候需要加锁,否则多个人修改同一条数据会报错
            # count += 1
            # lock.release()
        # 法2
            with lock:#自动加锁自动释放
                count += 1
    for i in range(2):
        t = threading.Thread(target=add)
        t.start()
    while threading.active_count() != 1:
        pass
    print(count)

     线程池

    安装threadpool模块(pip install threadpool)
    复制代码
    import threadpool,requests,pymongo
    client = pymongo.MongoClient(host='ip',port=27017)
    table = client['likun']['qq_group_likun']
    all_qq = [i.get('qq') for i in table.find()]
    
    url = 'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140'
    def down_img(qq_num):
        res = requests.get(url%qq_num).content
        with open('%s.jpg'%qq_num,'wb') as fw:
            fw.write(res)
    pool = threadpool.ThreadPool(200)#线程池的大小
    all_requests = threadpool.makeRequests(down_img,all_qq)#分配数据
    for r in all_requests:
        pool.putRequest(r)#发请求
    #[pool.putRequest(r) for r in all_requests]#同上两行
    pool.wait()#等待所有的线程运行完
    print('done,下载完成!')
    复制代码

     

    import threadpool
    import threading
    import hashlib
    import requests
    import os
    
    def md5(msg):
        msg = str(msg)
        m = hashlib.md5(msg.encode())
        return m.hexdigest()
    
    def down_load_pics(url):
        print(threading.current_thread())
        print('图片下载开始',url)
        r = requests.get(url)
        pic_name = md5(url)+'.jpg'
        if not os.path.exists('pics'):
            os.system('mkdir pics')
        pic_name = os.path.join('pics',pic_name)
        with open(pic_name,'wb') as fw:
            fw.write(r.content)
    
    urls=['https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140',
            'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140']
    
    pool = threadpool.ThreadPool(2)
    reqs = threadpool.makeRequests(down_load_pics,urls)#传方法名和一个列表
    for req in reqs:
        pool.putRequest(req)
    pool.wait()
    print('下载完成')

    进程(进程里可以启动线程,也要加锁)

    import multiprocessing
    import time
    
    def make_money(name):
        print('%s开始挣钱'%name)
        time.sleep(2)
    
    def start_process():
        p = multiprocessing.Process(target=make_money,args=['zjr'])
        p.start()
    
    if __name__ == "__main__":
        start_process()

    锁、多进程中加多线程

    import multiprocessing
    import time
    import threading
    # lock = multiprocessing.Lock()
    def test():
        print('多线程')
    
    def make_money(name):
        for i in range(10):
            t = threading.Thread(target=test)#多进程中加多线程
            t.start()
        print('%s开始挣钱'%name)
        time.sleep(2)
    
    def start_process():
        for i in range(5):
            p = multiprocessing.Process(target=make_money,args=['zjr'])
            p.start()
        print(multiprocessing.active_children())
        while len(multiprocessing.active_children()) != 1:
            pass
        print('运行结束')
    
    if __name__ == "__main__":
        start_process()

    进程池

    复制代码
     1 from multiprocessing import Process, Pool, active_children
     2 import pymongo,requests
     3 client = pymongo.MongoClient(host='118.11.3.40',port=27017)
     4 table = client['likun']['qq_group_likun']
     5 all_qq = [i.get('qq') for i in table.find()]
     6 
     7 url = 'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140'
     8 def down_img(qq_num):
     9     res = requests.get(url%qq_num).content
    10     with open('%s.jpg'%qq_num,'wb') as fw:
    11         fw.write(res)
    12 if __name__=='__main__':#必须写在这句底下,否则多进程用不了
    13     for qq in all_qq:
    14         # p = Process(target=down_img,args=(qq,))
    15         # p.start()
    16      # print(active_children())#打印活动的进程数
    17         pool = Pool(5)#指定进程池的大小
    18         list(pool.map(down_img,all_qq))#运行,使用进程池
    19         #map是个生成器
    复制代码

    什么时候用多线程,什么时候用多进程?

    cpu密集型任务:
    消耗cpu比较多
    排序、运算。。

    io密集型任务
    input/output
    写文件、读文件
    上传、下载
    python的多线程是利用不了多核cpu的
    全局解释器锁:GIL
    多进程是可以利用多核cpu的


  • 相关阅读:
    supermall遇到的问题
    github建立仓库
    【Teradata】9794 ERRAMPOUTOFPHYSPACE error解决方法
    MPP大规模并行计算数据库与分布式数据库的区别
    【English】20190515
    商业数据分析的四个层次
    学会学习(Learning how to learn)
    【English】20190513
    【Teradata】DEL语句产生的锁
    【Teradata】开启LockLogger与dumplocklog工具使用(含lokdisp工具说明)
  • 原文地址:https://www.cnblogs.com/Mezhou/p/13854492.html
Copyright © 2011-2022 走看看