2021-05-23

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @IDE      : PyCharm
# @Project  :mytest
# @File     : day30.py
# @Time     : 2019/9/2 8:04
# @Author   : wentao song

''''''
'''
作业:
    1. QQ聊天:使用Queue,Pipe,作为数据的载体,通过Process
        from multiprocessing import Process,Pipe
        import time,os
        # 通讯方向:
        # 单工、单项通信:收端只能听,发端只能发
        # 双工、通信两端,都可以进行随时的信息的发送与接收
        # 半双工:通信两端遵循一定的协议实现两端数据的双向通讯
        # 对讲机:P1,P2:调整频率相同,设定P1发送,P2接收 P1------>P2
        #         设置P1接收,P2发送 P1<---------P2
        def user1(ms):
            while True:
                # send方法发送的信息放在一个参数中
                ms.send(str(time.asctime())+str(os.getpid()))
                time.sleep(0.5)
        
        def user2(ms):
            while True:
                print(ms.recv())
        
        def mainFunc():
            #完成进程、管道创建,运行进程
            MS,MR = Pipe()
            P1 = Process(target=user1,args=(MS,))
            P2 = Process(target=user2,args=(MR,))
            P1.start()
            P2.start()
        
        if __name__ == '__main__':
            mainFunc()
    ------------------------------------------------
    2.性能对比:传统方式、进程、线程
        a. CPU性能,计算150万次算术运算
        b. 文件读写效率,完成对一个文件的500万次数据的写入和读取 
        ---------------------------------
        from multiprocessing import Process,Pool
        from threading import Thread
        import time
        
        def CalFunction():
            #150万次运算:
            x,y,z = 1,1,1
            while x<500000:
                x+=1
                y+=1
                z+=1
        
        def WriteFunction():
            with open('./text.txt',mode='w') as f:
                for x in range(500000):
                    f.write('write test!')
        
        def ReadFunction():
            with open('./text.txt', mode='r') as f:
                for x in range(500000):
                    f.readline()
        
        def IOFunction():
            WriteFunction()
            ReadFunction()
        
        #常规:
        def CalCommon():
            start_time= time.time()
            for i in range(10):
                CalFunction()
            end_time = time.time()
            print(end_time-start_time)
        
        def IOCommon():
            start_time = time.time()
            IOFunction()
            end_time = time.time()
            print(end_time - start_time)
        
        def CalThread():
            start_time = time.time()
            threads = []
            for i in range(10):
                T = Thread(target=CalFunction)
                threads.append(T)
                T.start()
            for i in threads:
                i.join()
            end_time = time.time()
            print(end_time-start_time)
        
        def IOThread():
            start_time = time.time()
            threads = []
            for i in range(10):
                T = Thread(target=IOFunction)
                threads.append(T)
                T.start()
            for i in threads:
                i.join()
            end_time = time.time()
            print(end_time-start_time)
        
        def CalPool():
            start_time = time.time()
            P = Pool(5)
            for i in range(10):
                P.apply_async(CalFunction)
            P.close()
            P.join()
            end_time = time.time()
            print(end_time-start_time)
        def IOPool():
            start_time = time.time()
            P = Pool(5)
            for i in range(10):
                P.apply_async(IOFunction)
            P.close()
            P.join()
            end_time = time.time()
            print(end_time-start_time)
        if __name__ == '__main__':
            # CalCommon()#0.6566615104675293
            # IOCommon()#21.214055061340332
            # CalThread()#0.6696805953979492
            # IOThread()  #46.42314839363098
            # CalPool()#0.5188260078430176
            IOPool()#11.366146087646484
    --------------------------------- 
    3. turtle模块实现科赫曲线:
    需要绘制长度为X的科赫曲线需要这么做:
        a.绘制长度X/3科
        b.向左转60°
        c.绘制长度X/3科赫曲线
        d.向右转120°
        e.绘制长度X/3科赫曲线
        f.向左转60°
        g.绘制长度X/3科赫曲线
            import  turtle
            
            def koch(T,n):
                if n<10:
                    T.fd(n)
                    return
                m = n/3
                koch(T, m)
                T.lt(60)
                koch(T, m)
                T.rt(120)
                koch(T, m)
                T.lt(60)
                koch(T, m)
            
            def Snow(t,n):
                for i in range(3):
                    koch(t,n)
                    t.rt(120)
            
            def mainFunc():
                T = turtle.Turtle()
                Snow(T,300)
                turtle.mainloop()
            
            if __name__ == '__main__':
                mainFunc() 
        ------------------------------------
    4.现有双向链表:{2,3,1,0,2,5,3},实现链表去重 
        class Node():
            def __init__(self, dataval, preval = None, nextval = None):
                self.dataval = dataval
                self.preval = preval
                self.nextval = nextval
        # 链表操作:删除前需:创建、添加、求长度等操作
        class Dlinklist():
            def __init__(self):
                self.header = None
        
            def listNode(self):
                nodes = []
                cur = self.header
                while cur != None:
                    nodes.append(cur.dataval)
                    cur = cur.nextval
                return nodes
        
            def getLength(self):
                cur = self.header
                length = 0
                while cur != None:
                    length+=1
                    cur=cur.nextval
                return length
        
            def headerInsert(self, newdata):
                NewNode = Node(newdata)
                if self.header == None:
                    self.header = NewNode
                else:
                    cur = self.header
                    self.header = NewNode
                    NewNode.nextval = cur
                    cur.preval = NewNode
        
            def endInsert(self, newdata):
                NewNode = Node(newdata)
                if self.header == None:
                    self.header = NewNode
                else:
                    cur = self.header
                    while cur.nextval !=None:
                        cur = cur.nextval
                    cur.nextval = NewNode
                    NewNode.preval = cur
        
            def indexInsert(self, newdata, index):
                if index == 1:
                    self.headerInsert(newdata)
                elif index > self.getLength():
                    self.endInsert(newdata)
                else:
                    cur = self.header
                    NewNode = Node(newdata)
                    for i in range(index):
                        cur = cur.nextval
                    second = cur.nextval # 断点后的节点,新插入节点位于second前,cur后
                    cur.nextval = NewNode
                    NewNode.preval = cur
                    NewNode.nextval = second
                    second.preval = NewNode
        
            def distinctNode(self):
                orgList = self.listNode()
                distinctList = []
                self.header = None
                for i in orgList:
                    if i not in distinctList:
                        distinctList.append(i)
                        self.endInsert(i)
            # def distinctNode(self):# 节点顺序排列问题
                # orgList = self.listNode()
                # distinctList = list(set(orgList))
                # self.header = None
                # for i in distinctList:
                #     self.endInsert(i)
        #2,3,1,0,2,5,3
        if __name__ == '__main__':
            dList = Dlinklist()
            dList.indexInsert(2,1)
            dList.indexInsert(3, 2)
            dList.indexInsert(1, 3)
            dList.indexInsert(0, 4)
            dList.indexInsert(2, 5)
            dList.indexInsert(5, 6)
            dList.indexInsert(3, 7)
            print(dList.listNode())
            dList.distinctNode()
            print(dList.listNode())
    ----------------------------------------------------
2. 线程
    加锁:Lock(), acquire加锁,release解锁
        from threading import Thread, Lock
        import os, time
        # 为子线程加锁,原始的并行改为串行执行,牺牲效率保证数据安全性
        # 为运行的线程添加编号:n,运行时打印
        def SubFunction(n,l):
            l.acquire()
            print('SubFunction is Running, PID:%s, number:%s'%(os.getpid(),n))
            time.sleep(0.1)
            print('SubFunction End, PID:%s, number:%s'%(os.getpid(),n))
            l.release()
        
        def MainFunc():
            threads = []
            lock = Lock()
            for i in range(100):
                T = Thread(target=SubFunction, args=(i,lock))
                threads.append(T)
                T.start()
                # T.join()
            for i in threads:
                i.join()
        
        if __name__ == '__main__':
            MainFunc()
    -------------------------------------------------
    死锁:加锁能够让外部任务处于等待状态。
        如果同时存在两个以上的进程或者线程同时加锁,就会导致因为加锁抢占资源
        而导致的进程之间相互等待的现象。死锁现象会导致程序无法继续向下执行。
        -----------------------------------------
            from threading import Thread, Lock
            import time
            
            lock1 = Lock()
            lock2 = Lock()
            
            class MyThread(Thread):
                def run(self):
                    self.func1()
                    self.func2()
            
                def func1(self):
                    lock1.acquire()
                    print('%s 拿到lock1锁'%self.name)
                    lock2.acquire()
                    print('%s 拿到lock2锁'%self.name)
                    lock2.release()
                    lock1.release()
            
                def func2(self):
                    lock2.acquire()
                    print('%s 拿到lock2锁'%self.name)
                    time.sleep(2)
                    lock1.acquire()
                    print('%s 拿到lock1锁'%self.name)
                    lock1.release()
                    lock2.release()
            
            
            if __name__ == '__main__':
                for i in range(10):
                    T = MyThread()
                    T.start() 
    ------------------------------------------------------
    递归锁:在python中为了支持在同一个线程中多次申请同意资源,加入RLock
        RLock内部存在Lock和计数器,计数器记录acquire次数,从而资源可以被多次
        acquire,直到一个线程所有acquire都被release,其他进程才能够获取资源
    -------------------------------------
        from threading import Thread, RLock
        import time
        
        lock1 = lock2 = RLock()
        
        class MyThread(Thread):
            def run(self):
                self.func1()
                self.func2()
        
            def func1(self):
                lock1.acquire()
                print('%s 拿到lock1锁' % self.name)
                lock2.acquire()
                print('%s 拿到lock2锁' % self.name)
                lock2.release()
                lock1.release()
        
            def func2(self):
                lock2.acquire()
                print('%s 拿到lock2锁' % self.name)
                time.sleep(2)
                lock1.acquire()
                print('%s 拿到lock1锁' % self.name)
                lock1.release()
                lock2.release()
        
        
        if __name__ == '__main__':
            for i in range(10):
                T = MyThread()
                T.start()
    ------------------------------------------------
    信号量:Semaphore
        与Lock一样,信号量也是一把锁,信号量可以设置数值,设定信号量为N
        在同一时间内,可以有N个任务一起执行 
        from threading import Thread, Semaphore
        import threading,time,os
        
        def func():
            sp.acquire()
            print('%s runngint,PID:%s'%(threading.current_thread().getName(), os.getpid()))
            time.sleep(3)
            print('%s end,PID:%s' % (threading.current_thread().getName(), os.getpid()))
            sp.release()
        
        if __name__ == '__main__':
            sp = Semaphore(5)
            for i in range(20):
                T = Thread(target=func)
                T.start()
    Semaphore:管理者一个内置的计数器,每当调用acquire时,内置计数器-1
                调用release时,内置计数器+1
                计数器不能小于0,当计数器为0,acquire将会阻塞其他进程调用release         
    ----------------------------------------------
    计时器:Timer,可以指定任务在预设时间后运行
        from  threading import Timer
    
        # 自定义函数
        def hello():
            print('Hello Timer!')
        # 实例化Timer对象,传入两个参数,参数1:延时时间,参数2,执行对象
        T = Timer(3, hello)
        # 执行定时器
        T.start()
    ----------------------------------------------
    线程的队列:Queue
        用法与进程相同,可以用在多个线程之间进行信息交换
    # 1.先进先出队列
        from queue import Queue
        
        q = Queue()
        for i in range(10):
            q.put(i)
        
        for i in range(10):
            print(q.get(), end=',')
        print()
    # 2.LifoQueue
        from queue import LifoQueue
        LQ = LifoQueue()
        for i in  range(10):
            LQ.put(i)
        for i in range(10):
            print(LQ.get(), end=',')
        print()
        # 3. PriorityQueue,具备设置优先级选项的队列
        from queue import PriorityQueue
        
        PQ = PriorityQueue()
        # put方法传入数据,数据类型是元组,元组的第一个参数是优先级
        # (通常是数字,也可以进行非数字比较),数字越小,优先级越高
        PQ.put((20,'a'))
        PQ.put((10,'b'))
        PQ.put((30,'c'))
    # 优先级高的成员先出队
        print(PQ.get())
        print(PQ.get())
        print(PQ.get())
'''
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @IDE      : PyCharm
# @Project  :mytest
# @File     : day31.py
# @Time     : 2019/9/3 8:01
# @Author   : wentao song

''''''
'''
1. 线程:
    多线程
    线程队列
    锁:死锁、递归锁、信号量

    比较进程、线程在计算和IO读写:
        运算:进程快,线程慢
        IO:  线程快,进程慢
    
    进程与线程的应用:
        多线程:多应用在IO密集型操作,比如socket通信、爬虫、web开发
        多进程:多应用与计算密集型操作,比如机器学习,金融分析等
    
    
    代码:运算
    # 1. 导入库和模块
        from multiprocessing import Process
        from threading import Thread
        import time, os
        
        #执行运算的函数,提供给子进程或者子线程调用
        def work():
            data = 0
            for i in range(100000000):
                data*=i
        
        # 在主进程中,创建子进程或者子线程
        # 执行多任务并发执行
        def mainFunc():
            # 接收需要执行并发任务的进程或者线程
            events = []
            # 查看计算机基本信息,显示计算机CPU核数
            print(os.cpu_count())
            start_time = time.time()
            #启动多个进程或者线程
            for i in range(4):
                # P = Process(target=work)    # run time is 7.812999248504639
                P = Thread(target=work)       #run time is 20.479247570037842
                events.append(P)
                P.start()
            for i in events:
                i.join()
            end_time = time.time()
            print('run time is %s'%(end_time-start_time))
        
        if __name__ == '__main__':
            mainFunc()
        -------------------------------------------------------
    #IO运算    
            from threading import Thread
            from multiprocessing import Process
            import os,time
            
            #函数,被子进程或者子线程调用
            def work():
                time.sleep(2)
                print('------>')
            
            def mainFunc():
                events = []
                print(os.cpu_count())
                start_time = time.time()
                for i in range(400):
                    # T = Thread(target=work) #run time is 2.0476455688476562
                    T = Process(target=work)  #run time is 15.327229976654053
                    events.append(T)
                    T.start()
                for i in events:
                    i.join()
                end_time = time.time()
                print('run time is %s'%(end_time-start_time))
            
            if __name__ == '__main__':
                mainFunc()

2. 事件对象:Event
        线程中提供的方法:用来控制线程执行状态
        原因:多个线程在一个进程中执行。线程状态未知,存在不可预测的风险。
        
        Event:事物处理对象管理线程,内置方法有,
                    is_set(), set(), clear(),wait()
        is_set() 设置线程内部标志为True时,返回False
        set()    将进程内部标志设置为Ture,此时所有等待它为Ture的线程会被唤醒
                线程调用wait()方法时,不会阻塞
        clear()  将进程内部标志设置为False,随后调用wait()将进程阻塞
        wait(timeout=None) 执行阻塞,如果线程内部标志为Ture立即返回,
                否则执行阻塞
        --------------------------------------------------------
        练习:
            # 需求:使用线程实现生产者、消费者模型
            # 1. 以继承方式实现线程创建,线程之间数据交换通过消息队列
            # 2. 两个线程设置,生产者为守护线程: 守护线程负责生产包子,消费者线程负责买包子
            # 3. 买包子需要钱,一个包子一块钱,一共七块钱,如果没钱了,停止购买
            # 4. 设置消息队列长度为5 
            -----------------------------------------------------
            import threading, queue, time
            
            class Producer(threading.Thread):
                # 重写run方法
                def run(self):
                    # 标记包子数量
                    global num
                    while True:
                        #判断队列为空
                        if goods.empty():
                            #阻塞,生产包子
                            event.clear()
                            for i in range(5):
                                goods.put('包子-'+str(num))
                                print('生产了包子-{0}.'.format(str(num)))
                                num+=1
                                time.sleep(0.5)
                            event.set()
            
            class Consumer(threading.Thread):
                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    #增加属性,7元钱
                    self.monkey = 7
                def run(self):
                    while self.monkey:
                        #设置线程阻塞
                        event.wait()
                        self.monkey-=1
                        print('{0}买了一个{1}。'\
                              .format(threading.current_thread().getName(), goods.get()))
                        time.sleep(1)
                    print('{0}没钱了,回家。'.format(threading.current_thread().name))
            def mainFunc():
                P = Producer(daemon=True)
                #在继承的类中传入人名
                C1 = Consumer(name='关一峰')
                C2 = Consumer(name='周涛')
                P.start()
                C1.start()
                C2.start()
                C1.join()
                C2.join()
            if __name__ == '__main__':
                # 引入Event事件
                event = threading.Event()
                # 引入队列,作为数据交换载体
                goods = queue.Queue(5)
                # 计数器
                num = 0
                mainFunc()  
    ---------------------------------------------------------
进程池与线程池:
    池:声明创建进程或者线程的个数,通过控制创建数量,在节省系统资源的
        前提下,提升代码执行效率
    concurrent.futures: 模块,提供高度封装的异步调用接口
            ThreadPoolExecutor:线程池,提供异步调用
            ProcessPoolExecutor :进程池,提供异步调用
    
        基本方法:
            submit():提交异步任务
            map(): 取代for循环submit的操作
            shutdown():相当于执行 pool.close()+pool.join()
                关闭进程或线程池,执行进程或线程
            result():获取结果
            add_done_callback():回调函数
    
        from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
        import os,time
        
        def work():
            print('%s is running'%os.getpid())
            time.sleep(2)
            print('%s is end!' % os.getpid())
        
        def mainFunc():
            # 创建进程池或线程池,max_workers指定创建池子的大小
            # Executor = ThreadPoolExecutor(max_workers=3)
            Executor = ProcessPoolExecutor(max_workers=3)
            for i in range(11):
                Executor.submit(work)
            Executor.shutdown()
        
        if __name__ == '__main__':
            mainFunc()
    -----------------------------------------------------
回调函数:
    concurrent.futures,回调函数可以为提交执行的进程或线程绑定一个函数
    在进程或者线程执行结束,触发这个函数,并且进程或线程接受返回值作为参数
    
    提交任务的方法:
        1. 同步调用:提交任务后,原地等待任务执行完毕,拿到的结果继续执行。
            同步调用会导致程序串行
        2. 异步调用:提交任务之后,无需等待任务执行结束 
    ----------------------------------------------------------
    同步调用实例:
            from concurrent.futures import ThreadPoolExecutor
            import time,random
            
            def EatStatus(name):
                print("%s 正在吃包子"%name)
                time.sleep(random.randint(1,2))
                res = random.randint(1,20)*'#'
                return {'name':name,'res':res}
            
            def EatNum(food):
                name = food['name']
                size = len(food['res'])
                print('%s 吃了 %s个包子'%(name, size))
            
            #在线程池中创建线程,线程执行后,调用回调函数add_done_callback
            def mainFunc():
                pool  = ThreadPoolExecutor(13)
                # 提交线程任务同时获取线程执行结果,同时使用EatNum进行同步调用
                P1 = pool.submit(EatStatus, '关一峰').result()
                EatNum(P1)
                P2 = pool.submit(EatStatus,'孙一山').result()
                EatNum(P2)
                P3 = pool.submit(EatStatus, '何立国').result()
                EatNum(P3)
            
            if __name__ == '__main__':
                mainFunc()
    ---------------------------------------------------
        # 异步调用
            from concurrent.futures import ThreadPoolExecutor
            import random,time
            # 方法不变
            def EatStatus(name):
                print("%s 正在吃包子"%name)
                time.sleep(random.randint(1,2))
                res = random.randint(1,20)*'#'
                return {'name':name,'res':res}
            # 改写吃包子方法
            def EatNum(food):
                # 异步调用固定写法
                food = food.result()
                name = food['name']
                size = len(food['res'])
                print('%s 吃了 %s个包子' % (name, size))
            
            
            def mainFunc():
                pool = ThreadPoolExecutor(13)
                # 提交线程任务,EatNum进行异步调用
                pool.submit(EatStatus, '关一峰').add_done_callback(EatNum)
                pool.submit(EatStatus, '孙一山').add_done_callback(EatNum)
                pool.submit(EatStatus, '何立国').add_done_callback(EatNum)
            
            if __name__ == '__main__':
                mainFunc()
        --------------------------------------------------
    map:
        from concurrent.futures import ThreadPoolExecutor
        #爬虫库
        import requests
        
        """
        # 采用requests爬虫库,爬取列表第一项数据
        response = requests.get(URLS[0])
        #从网站返回的数据对象中打印其文本信息:.text
        print(response.text)
        """
        def task(url,timeout=10):
            return requests.get(url, timeout=timeout)
        
        def mainFunc():
            pool = ThreadPoolExecutor(max_workers=3)
            results = pool.map(task, URLS)
            for result in results:
                print(len(result.text))
        if __name__ == '__main__':
            URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com']
            mainFunc()
3. 协程:
        单线程下实现的并发。也称为微线程。协程是一种用户态的轻量级线程,协程是由用户
        自己控制调度的。线程是CPU调度的执行单元。
    优点:
        无需线程上下文切换的开销,程序员自行控制
        高并发,高扩展,低成本
    缺点:
        无法利用多核的资源,协程本质上是一个单线程
        在执行阻塞操作时,会阻塞掉协程整个程序
    -----------------------------------------------------------
    # 生成器:yield,next
    # 生成器协程,并发执行func1与func2,效率较低
    import time
    
    def func1():
        while True:
            yield
    
    def func2():
        g = func1()
        for i in range(100000000):
            next(g)
    
    def mainFunc():
        start_time = time.time()
        func2()
        stop_time = time.time()
        print(stop_time-start_time)
    
    if __name__ == '__main__':
        mainFunc()      
'''
1. yeild可以保存状态,yield状态保存与操作系统保存线程很像,
    但是yeild是代码级别的控制,更加轻量级
2. send可以把函数执行结果传给另外一个函数,借此实现单线程内部并发运行
def consumer(name):
    print('开始吃包子。。。')
    while True:
        print('consumer %s 需要包子'%name)
        baozi = yield #接收producer发送过来的数据
        print('%s 吃了 %s个包子'%(name, baozi))

def producer(obj):
    obj.send(None) #必须发送None内容到consumer
    for i in range(3):
        print('producer 正在做%s个包子'%i)
        obj.send(i)

if __name__ == '__main__':
    person1 = consumer('Alex')
    producer(person1)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @IDE      : PyCharm
# @Project  :mytest
# @File     : day32.py
# @Time     : 2019/9/4 8:00
# @Author   : wentao song

'''
1. 协程
    ①.生成器, yield\next\send
    ②.greenlet模块
    ③.gevent,实现、调用
2. Socket网络通信
    ①. 网络知识储备
    ②.CS架构与BS架构
    ③.socket网络编程
'''
# 使用yield生成器模拟协程:
# 协程:是单线程下实现的并发,又称为为线程。
#         是一种用户级别的轻量级线程,协程是由用户执行调度的。

# import time
#
# def func1():
#     while True:
#         yield
#
# def func2():
#     g = func1()
#     for i in range(100000000):
#         i+=1
#         next(g)
#
# def mainFunc():
#     start = time.time()
#     func2()
#     stop = time.time()
#     print(stop-start)
#
# if __name__ == '__main__':
#     mainFunc()


# greenlet是一个小型独立伪线程。可以把它想象成栈的成员,栈底是初始调用的函数
# 栈顶是greenlet的暂停位置。使用greenlet创建的不同堆栈可以在暂停状态执行跳转,
# 跳转到另外一个greenlet

# 方法介绍
# 1. greenlet.greenlet是一个数据类型
# 2. greenlet(run=None, parent=None)
#     创建greenlet对象,run是指需要执行的函数,传参可以省略掉run=,
#     如果之传入一个参数,代表要执行执行的函数
# 3. greenlet.getcurrent()
#     返回当前greenlet,也就是那个函数在被执行
# 4. greenlet.GreenletExit
#     特定的异常出现时,不会关联parent指定的函数
# 5. greenlet.switch(),在greenlet对象之间执行跳转
#执行switch跳转时,任务跳转并保留当前位置,下一次执行,从当前位置开始执行
# from greenlet import greenlet
#
# def func1():
#     print('Func1 running')
#     g2.switch()
#     print('Func2 end')
#     g2.switch()
#
# def func2():
#     print('Func2 running')
#     g1.switch()
#     print('Func1 end')
#
# if __name__ == '__main__':
#     # 通过greenlet 跳转机制,实现func1与func2函数之间跳转
#     g1 = greenlet(func1)
#     g2 = greenlet(func2)
#     g1.switch()
#
# # 参照上述跳转,
# #   实现在两个函数之间的任务往复跳转
# # 函数1 自增一亿次
# # 函数2 自乘一亿次

# gevent实现的协程
# gevent是一个第三方库,可以实现协程调用方式,它是以扩展的C模块形式
#   接入python的轻量级协程,gevent全部运行的主程序都在进程内部,
#   执行协程模式的调度。
# gevent会主动的识别程序内部IO操作,当子程序遇到IO阻塞后,会切换到其他子程序
# 如果所有子程序都进入IO阻塞,则阻塞
# from gevent import monkey
# monkey.patch_all()
# import gevent, time
#
# def eat(name):
#     print('%s eatting apple'%name)
#     time.sleep(2)
#     # gevent.sleep(2)
#     print('%s eatting banana'%name)
#
# def play(name):
#     print('%s playing basketball'%name)
#     time.sleep(3)
#     # gevent.sleep(3)
#     print('%s playing game'%name)
#
# def mainFunc():
#     g1 = gevent.spawn(eat, 'Alex')
#     g2 = gevent.spawn(play, 'Alex')
#     g1.join()
#     g2.join()
#     print('mainFunc End!')
#
# if __name__ == '__main__':
#     mainFunc()

#1. gevent在单线程并发执行时,效率更高,因为它会在IO阻塞时,执行任务跳转
#2. gevent,能够识别 由 gevent.sleep()造成的IO阻塞。其他类型的阻塞无法识别
#3. 使用如下代码,可以识别所有类型的IO阻塞问题
# from gevent import monkey
# monkey.patch_all()
#--------------------------------------------------------------------
# 网络通信部分:
# 基础知识: PC网络设备,无线、有线网卡,网口
#
# 客户端软件基于网络,发送一条信息给服务端,流程:
# 1. 客户端软件,产生数据,存放在客户端软件的内存中,然后调用接口将自己内存中存储的
#     数据发送或者拷贝给操作系统的内存
#
# 2. 客户端操作系统收到数据后,按照客户端指定的规则(协议),调用网卡发送数据
#
# 3. 网络传输数据
#
# 4. 服务端软件调用系统接口,想要将操作系统内存中的数据拷贝到自己的内存中
#
# 5. 服务端操作系统收到4的指令后,使用与客户端相同的规则(协议)从网卡中将数据拷贝到
#     服务端软件
#
# 规则:高低电平信号的组合方式
# 网线数据:高低电平,高代表1,低代表0,
#     1111 0001 0100 0000
#     11110001 01000000

# 互联网协议:根据划分方式分为三类
# 第一类:OSI七层模型
# 第二类:tcp/ip 五层模型
# 第三类:tcp/ip 四层模型
#
# TCP/IP五层模型:
#
# 物理层:计算机之间想要完成网络通信,就必须接入网络(局域网、广域网),
#         言外之意,计算机必须联网组网
#     网络介质:光缆、电缆、双绞线、无线通讯
#
#     功能: 基于电器特性发送高低电平,高电平1,低电平0
#
# 数据链路层:
#     数据链路层由来:单纯的电信号101010000111毫无意义,必须规定电信号是多少位一组
#                 每组是什么含义
#     功能:定义电信号的分组方式
#
#     # RS232,485, 422,modbus can spi zigbee wifi
#
#     以太网协议:
#         早期各个公司都有自己的分组方式,为了统一,出现了以太网协议Ethernet
#
#     规定:
#         每组电信号构成一个数据包,也可以称作帧
#         每一帧数据分为:包头header,数据data
#
#         EE 4A BD AF 00 01 57 FF 41
#         EE 4A BD AF 41 19 64 F1 00
#
#         header包含 固定18个字节
#             发送者/源地址:6字节
#             接收者/目的地址:6字节
#             数据类型:6字节
#         data:最短46字节,最长1500字节
#             data就是数据包中的有效信息
#     mac地址:
#             物理地址,是计算机网卡的编号
#     查看方式:ipconfig -all
#     结果
#        物理地址. . . . . . . . . . . . . : 68-F7-28-EE-C4-C6
#     广播:
#         有了mac地址,同一个网络中两台计算机就可以通信了
#         发端发信息到整个网络内的所有计算机 称为广播
#
# 网络层:
#     有了Ethernet,mac地址,广播的通信方式后,世界上的计算机就可以通信了。
#     问题是世界范围内联网是由一个个彼此隔离的小局域网组成的
#     如果采用以太网广播方式传输数据,那么所有网络内的计算机都可以收到信息
#     这种通信效率低,安全性差
#
#     引入一套全新的地址区分广播域(发送广播数据)和子网(发送点对点数据),
#     这套地址称为网址(IPV4/IPV6)
#
#     # 网址中每一位最大值是255,最小值是0
#     # 192.168.1.x: 256台
#     # 192.168.x.x 256**2台
#     # 220.x.x.x  256**3台
#     ICMP(网络控制报文)协议
#         当传送IP数据包发生错误时,比如:主机不可达、路由不可达等等,ICMP协议
#         就会把错误信息封装数据包返回给主机。比如ICMP协议中的ping命令
#
# 传输层:TCP/UDP
#     网络层IP可以帮助我们区分子网 广播域,以太网可以通过mac地址帮助我们找到主机,
#     应用程序怎么办?在PC上打开QQ 淘宝等应用,如何处理?
#
#     我们需要通过主机上的端口号实现以上要求。
#
#     传输层创建端口的范围:
#     端口表达范围:0~65535,0~1023为系统占用端口
#
#     windows下查看端口占用情况
#         netstat  -ano|findstr  "3306"
#     查看PID被哪个服务占用
#         tasklist |findstr  "23400"
#
# 应用层:
#     用户使用的应用程序位于TCP/IP五层架构的应用层,互联网开发的与处于应用层开发
#     由于应用层软件需要的数据格式都各不相同,因此用用层必须规定好数据的组织形式
#     规定应用程序的数据格式
#     TCP协议可以为各种应用程序提供数据,比如说 Email FTP 浏览器等等
#
# 传输层的C\S架构与B\S架构
#     客户端的英文名称:Client
#     浏览器的英文名称:Browser
#     服务器的英文名称:Server
#     C\S架构就是 Client\Server架构, B\S架构就是 Browser\Server架构
#
#     ①. 硬件C\S架构:电脑与连接电脑的打印机
#     ②. 软件C\S架构:QQ 微信 暴风影音 优酷都是C\S架构
#     ③. 软件B\S架构:基于浏览器访问的软件,数据在浏览器与浏览器服务器之间传输
#
# Socket实现网络通信:
#     定义: socket是应用层与TCP/IP协议族通信的中间的抽象层,它是一组接口。它把
#             复杂的TCP/IP协议族隐藏起来,为用户只提供接口。Socket只负责组织数据
#
#     分类:
#         1. 基于文件类型的套接字 AF_UNIX
#         2. 基于网络的套接字 AF_INET
#
#     套接字类型:
#         socket.SOCK_STREAM      TCP
#         socket.SOCK_DGRAM       UDP
#         socket.SOCK_RAW         原始套接字,
#                     当普通套接字无法处理ICMP\IGMP类型网络报文,使用socket.SOCK_RAW
#         socket.SOCK_SOCKRDM     是一种可靠的UDP形式,即保证提交数据报也不保证顺序
#
#     TCP与UDP对比:
#         TCP(Transmission Control Protocol)是一种可靠的、面向连接的协议,传输效率低
#         全双工的通信,面向字节流
#
#         UDP(User Datagram Protocol)是一种不可靠,无连接,传输效率高,可以实现一对一
#         一对多 多对多的通信,它的特点:尽最大努力服务,无阻塞控制。
#
#     TCP工作流程:
#         服务器
#         1. 服务器初始化socket
#         2. 绑定端口
#         3. 端口监听
#         4. 调用accept阻塞,等待用户连接
#
#         客户端
#         1. 初始化socket
#         2. 连接服务器
#         3. 如果连接成功,客户端与服务器就建立了连接
#
#     socket模块的函数用法:
import socket
# socket.socket(socket_family, socket_type,proto=0)
# socket_family 可以是AF_UNIX或者AF_INET
# socket_type  可以使SOCK_STREAM 或者SOCK_DGRAM
# protocol 一般不做设置,默认值0

#获取TCP格式套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 服务端:
tcpSock.bind()   #绑定 主机,端口号到套接字
tcpSock.listen() #执行TCP监听

#客户端:
tcpSock.connect()  #主动初始化TCP服务器连接
tcpSock.connect_ex() # connect()函数的拓展版本,在出错时返回出错码,而不是跑出异常

#公共用途的套接字:
tcpSock.recv()  # 接收TCP数据
tcpSock.send()  # 发送TCP数据
tcpSock.sendall()# 发送完整的TCP数据

udpSock.recvfrom()  #接收UDP数据
udpSock.sendto()    #发送UDP数据

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值