• python学习之多线程多进程


    python基础

    进程&线程

      进程是一组资源的集合,运行一个系统就是打开了一个进程,如果同时打开了两个记事本就是开启了两个进程,进程是一个笼统的概念,进程中由线程干活工作,由进程统一管理

      一个进程至少有一个线程,如果没有,进程也就没有了,线程分为主线程,子线程,而主线程负责调度,支配子线程运行,在代码运行时,主线程分配子线程去干活,而主线程分配之后继续执行后面代码,这时需要我们join一个,主线程等待子线程全部运行完之后,再运行后面代码

    单线程  系统默认就起好一个进程,也就是起了一个进程,一个线程

    import time
    # 单线程    时间叠加了,运行速度会变慢
    start = time.time()
    def run():
        time.sleep(5)
        print("over")
    run()
    run()
    end = time.time()
    all_time = end - start
    print(all_time)

    多线程下载网页

    # 单线程下载网页
    import threading, requests
    def downloads(url, file_name):
        res = requests.get(url)
        with open(file_name, 'wb') as wf:
            wf.write(res.content)
    url = {'rainbol1': 'https://www.cnblogs.com/RainBol/',
           'rainbol2': 'https://www.cnblogs.com/RainBol/'}
    for file_name, url in url.items():
        t1 = threading.Thread(target=downloads,
                              args=(url, file_name))  # target指定一个线程让它来帮助我执行,args执行target中的参数,只有一个用args=(url,)
        t1.start()  # t1.start启动一个线程
        t1.join()  # 等待子线程工作完毕,主线程再继续运行

    多线程  一个进程下面有多个线程

    # 由于线程分为主线程和子线程,所以我们要考虑他们之间的同步
    # 方法1    for循环实现
    import threading, time
    def run1():
        time.sleep(5)
        print("over")
    start = time.time()
    list1 = []  # 定义一个list
    for i in range(20):  # 定义要开启20个线程
        t1 = threading.Thread(target=run1)
        t1.start()
        list1.append(t1)  # 添加一个子线程到列表中
    for t1 in list1:  # 主线程走到这一步子线程都在执行time.sleep()方法,如果继续执行就代码就会走完,所以要等待所有子线程全部运行完毕
        t1.join()
    end = time.time()
    print(end - start)
    # 方法2    while循环实现
    import threading, time
    def run1():
        time.sleep(5)
        print("over")
    start = time.time()
    for j in range(20):  # 定义要开启20个线程
        t1 = threading.Thread(target=run1)
        t1.start()
    while threading.activeCount() != 1:  # 如果只有一个线程的时候说明只有一个主线程了,此时循环结束,执行后面代码,否则继续循环
        pass
    end = time.time()
    print(end - start)
    # 方式3    
    class Mythread(threading.Thread):
        def run(self):#方法必须叫run
            time.sleep(5)
            print("over")
    for k in range(20):
        res = Mythread()
        res.start()#调用必须叫start

    守护线程

      如果你想等待子线程完成再退出,那就什么都不用写,或者显示地调用thread.setDaemon(False),设置daemon的值为false。新的子线程会继承父线程的daemon标志。整个Python会在所有的非守护线程退出后才会结束,即进程中没有非守护线程存在的时候才结束。

    import time,threading
    #守护线程
    def shouhu():
        time.sleep(5)
        print("555")
    for l in range(10):
        res = threading.Thread(target=shouhu)
        res.setDaemon(True)#定义守护线程,当定义了这句话表示开启守护线程
        res.start()
    print("守护线程结束")

      多个线程同时操作同一个数据的时候一定要加锁

    import threading
    
    # 锁,记得加锁完一定要解锁,不然出现死锁现象
    num = 0
    lock = threading.Lock()  # 实例化一把锁
    def aaa():
        global num
        lock.acquire()  # 加锁
        num += 1
        lock.release()  # 解锁
      #或者两者一样
      #with lock:
        #num +=1 for i in range(100): t = threading.Thread(target=aaa) t.start() while threading.activeCount() != 1: pass print(num)
    在python2中一定要加锁,python3中会自动加锁解锁,但是为了规范还是加上比较好

    多进程  多个进程,每个进程下面只有一个线程工作

      狭隘的来说进程是根据计算机的cpu颗粒数来算的,我们通常做性能测试可以模拟1000个线程,那是cpu在做上下文切换,实际上4核cpu也就是同时只能运行4个线程,我们肉眼根本看不出来误以为计算机开了1000个并发.所以说使用进程的多少取决于你使用的cpu

      而python在语言设计上由于GIL全局解释器锁,只能用cpu的一个核心来处理https://www.cnblogs.com/stubborn412/p/4033651.html

      为什么时候用多进程什么时候用多线程:

      cpu密集型任务(循环处理,计数,运算等):多进程可以利用多核cpu,多启动一个进程下一个线程工作,可以大大提交cpu的处理速度,而多线程来回切换极大消耗cpu的资源

      IO密集型任务(网络爬虫,文件处理等):多线程可以充分利用等待时间,利用其它线程执行代码,而多进程也就是单线程进行IO操作只会傻傻等待

    from multiprocessing import Process
    import time
    def run():
        time.sleep(50)
        print("Zzzzz")
    if __name__ == '__main__':
        for i in range(8):  # 启动两个进程
            p = Process(target=run)
            p.start()

    多进程&多线程应用

    from multiprocessing import Process,Manager  #Manager.dict()可以多进程之间共享数据
    import threading
    import time
    def run_threading():
        time.sleep(60)
        print("Zzzzz---%s" % threading.current_thread())  # 打印线程名称
    def xiancheng():
        for j in range(10):  # 启动10个线程
            p = threading.Thread(target=run_threading)
            p.start()
    if __name__ == '__main__':
        for i in range(10):  # 启动10个进程
            p = Process(target=xiancheng)
            p.start()

      10个为子进程,1一个为主进程,一个为pycharm进程

    requests

    import requests
    import nnlog
    class MyRequest:
        log_file_name  = 'MyRequest.log'#日子文件名
        time_out = 10 #请求超时时间
        def __init__(self,url,data=None,headers=None,file=None):
            self.url = url
            self.data = data
            self.headers = headers
            self.file = file
        def post(self):
            try:
                req = requests.post(self.url,data=self.data,headers=self.headers,
                                    files=self.file,timeout=self.time_out)
            except Exception as e:
                res = {"status":0,"err_msg":e.args}  #0代表请求失败
            else:
                try:
                   res = {"status":1,"data":req.json()} #1代表返回的json
                except Exception as e:
                    res = {"staus":2,"data":req.text} #2代表返回不是json
            log_str = 'url: %s 请求方式:post  data:%s ,返回数据:%s'%(self.url,self.data,res)
            self.write_log(log_str)
            return res
    
        def get(self):
            try:
                req = requests.get(self.url,params=self.data,headers=self.headers,timeout=self.time_out)
            except Exception as e:
                res = {"status":0,"err_msg":e.args}  #0代表请求失败
            else:
                try:
                   res = {"status":1,"data":req.json()} #1代表返回的json
    
                except Exception as e:
                    res = {"staus":2,"data":req.text} #2代表返回不是json
            log_str = 'url: %s get请求 data:%s ,返回数据:%s'%(self.url,self.data,res)
            self.write_log(log_str)
            return res
    
        @classmethod
        def write_log(cls,content):
            log = nnlog.Logger(cls.log_file_name)
            log.debug(content)
    #ThreadPoolExecutor线程池的submit
    import time
    import requests
    from concurrent.futures import ThreadPoolExecutor, wait
    
    def time_ji(fuc):
        def wrapping(*args, **kwargs):
            start = time.time()
            fuc(*args, **kwargs)
            res = time.time() - start
            print(res)
            return
    
        return wrapping
    hread = ThreadPoolExecutor(max_workers=2)
    page = [x for x in range(1, 6)]
    urls01 = ['http://rainbol.cn?page=%s' % i for i in page]
    urls01.append('http://www.baidu.com')
    list01 = []
    @time_ji
    def run(i):
        res = requests.get(i)
        print(i, str(len(res.text)) + '字节')
    for i in urls01:
        result_submit = thread.submit(run,i)
        list01.append(result_submit)
    wait(list01)  # 等待其他线程工作完成后再执行下面操作
    print('都执行完了')
    #submit:
    # http://rainbol.cn?page=1 35489字节
    # 0.07800006866455078
    # http://rainbol.cn?page=2 35712字节
    # 0.12480020523071289
    # http://rainbol.cn?page=3 35534字节
    # 0.07800030708312988
    # http://rainbol.cn?page=4 35495字节
    # 0.06240034103393555
    # http://www.baidu.com 2381字节
    # 0.14039993286132812
    # http://rainbol.cn?page=5 25010字节
    # 0.32760047912597656
    
    

    #ThreadPoolExecutor线程池的submit import time def time_ji(fuc): def wrapping(*args, **kwargs): start = time.time() fuc(*args, **kwargs) res = time.time() - start print(res) return return wrapping import requests from concurrent.futures import ThreadPoolExecutor, wait thread = ThreadPoolExecutor(max_workers=2) page = [x for x in range(1, 6)] urls01 = ['http://rainbol.cn?page=%s' % i for i in page] urls01.append('http://www.baidu.com') list01 = [] @time_ji def run(i): res = requests.get(i) print(i, str(len(res.text)) + '字节') result_map = list(thread.map(run, urls01)) print('都执行完了') #http://rainbol.cn?page=2 35712字节 #0.09200549125671387 #http://rainbol.cn?page=1 35489字节 #0.12100696563720703 #http://rainbol.cn?page=3 35534字节 #0.08300471305847168 #http://rainbol.cn?page=4 35495字节 #0.10100579261779785 #http://www.baidu.com 2381字节 #0.06100344657897949 #http://rainbol.cn?page=5 25010字节 #0.28101587295532227 #都执行完了 #ProcessPoolExecutor进程 from concurrent.futures import ProcessPoolExecutor, wait import time import requests page = [x for x in range(1, 6)] urls01 = ['http://rainbol.cn?page=%s' % i for i in page] urls01.append('http://www.baidu.com') def run(i): start = time.time() res = requests.get(i) print(i, str(len(res.text)) + '字节') print(time.time()-start ) process1 = ProcessPoolExecutor(max_workers=2) if __name__ == '__main__': #必须加main不然会报错 list01 = [] for i in urls01: result_map = process1.submit(run, i) list01.append(result_map) wait(list01) print('都执行完了')

    http://rainbol.cn?page=1 35489字节
    0.08200478553771973
    http://rainbol.cn?page=2 35712字节
    0.10700583457946777
    http://rainbol.cn?page=3 35534字节
    0.09300518035888672
    http://rainbol.cn?page=4 35495字节
    0.08600473403930664
    http://rainbol.cn?page=5 25010字节
    0.06000328063964844
    http://www.baidu.com 2381字节
    0.06800413131713867
    都执行完了

     同步非阻塞/异步非阻塞/回调函数

    # 进程池
    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    import os, time, random
    
    
    def func(a, b):
        print(os.getpid(), 'start', a, b)
        time.sleep(random.randint(1, 4))
        print(os.getpid(), 'end')
        return a * b
    
    
    def roll_back_func(ret):
        print(ret.result())
    
    
    if __name__ == '__main__':
        # 开启了4个进程
        tp = ProcessPoolExecutor(4)
        funter = {}
        # for i in range(20):同步非阻塞打印
        #     ret = tp.submit(func, i, b=i + 1)
        #     funter[i] = ret
        # for key in funter:  #
        #     print('结果', key, funter[key].result())
    
        for i in range(20):  # 异步非阻塞打印
            ret = tp.submit(func, i, b=i + 1)
            ret.add_done_callback(
                roll_back_func)  # 异步阻塞 给ret绑定一个回调函数,等待ret的任务有了结果之后立即执行roll_back_func函数,这样的好处是当异步执行有结果之后立即拿到结果,而不用按照顺序接收结果

    版权声明:本文原创发表于 博客园,作者为 RainBol 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

  • 相关阅读:
    面试题--十进制转换成2进制
    c++基础--如何将函数作为参数传递
    面试题--完全二叉树的的最后一层的最右节点
    数据库原理--故障恢复
    数据库原理--事务并发控制
    数据库原理--事务(一)
    数据库原理--1nf 2nf 3nf
    数据库原理--外键和主键
    数据库原理--函数依赖和范式
    人人都有极客精神
  • 原文地址:https://www.cnblogs.com/RainBol/p/9980099.html
Copyright © 2020-2023  润新知