• day 40 线程队列、线程定时器、进程池和线程池、同步与异步、用多线程来写socket服务端与客户端


    线程队列

      #先进先出

    import queue
    q = queue.Queue()#
    q.put('123')
    q.put('qweqwe')
    print(q.get())
    print(q.get())
    # print(q.get())
    q.task_done()
    q.join()


    #后进先出
    q = queue.LifoQueue() #堆栈 先进后出
    q.put('粉红色的背心儿')
    q.put('粉红色的裤子')
    q.put('欧文的各种设备')
    print(q.get())
    print(q.get())
    print(q.get())
    # 欧文的各种设备
    # 粉红色的裤子
    # 粉红色的背心儿


    #按优先级出
    q = queue.PriorityQueue() # 可以根据优先级取数据
    # 通常这个元组的第一个值是int类型
    q.put((50,'许成'))
    q.put((80,'赵军'))
    q.put((1,'宇力'))
    print(q.get())
    print(q.get())
    print(q.get())
    # (1, '宇力')
    # (50, '许成')
    # (80, '赵军')


    线程定时器
    from threading import Thread,Timer,currentThread
    import time


    def task():
    print('线程执行了')
    print('线程结束了')
    print(currentThread().name)


    t = Timer(4,task) # 过了4s后再执行线程中的代码
    t.start()



    进程池和线程池
    进程池线程池:
    池的功能限制是限制并发的进程数或线程数.
    什么时候限制?
    当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
    应该限制我进程数或线程数,从保证服务器不崩.


    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import currentThread
    from multiprocessing import current_process
    import time

    def task(i):
    print(f'{currentThread().name} 在执行任务 {i}')
    # print(f'进程 {current_process().name} 在执行任务 {i}')
    time.sleep(1)
    return i**2

    if __name__ == '__main__':
    pool = ThreadPoolExecutor(4) # 池子里只有4个线程
    # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
    fu_list = []
    for i in range(20):
    # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
    future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
    # print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
    fu_list.append(future)
    pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
    for fu in fu_list:
    print(fu.result())

    #同步与异步
    理解为提交任务的两种方式
    同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码,
    异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.


    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import currentThread
    from multiprocessing import current_process
    import time

    def task(i):
    print(f'{currentThread().name} 在执行任务 {i}')
    # print(f'进程 {current_process().name} 在执行任务 {i}')
    time.sleep(1)
    return i**2

    def parse(future):
    # 处理拿到的结果
    print(future.result())

    if __name__ == '__main__':
    pool = ThreadPoolExecutor(4) # 池子里只有4个线程
    # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
    fu_list = []
    for i in range(20):
    # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
    future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
    future.add_done_callback(parse)
    # 为当前任务绑定了一个函数,在当前任务执行结束的时候会触发这个函数,
    # 会把future对象作为参数传给函数
    # 这个称之为回调函数,处理完了回来就调用这个函数.
    ##经实际运行发现,只有当4个线程全都开启时,线程池才算真正建立,并且绑定函数会由被绑定线程来执行;进程中,绑定函数由主进程运行

    协成
    python的线程用的是操作系统原生的线程
    协程:单线程下实现并发
    并发:切换+保存状态
    多线程:操作系统帮你实现的,如果遇到io切换,执行时间过长也会切换,实现一个雨露均沾的效果.

    #什么样的协程是有意义的?
    遇到io切换的时候才有意义
    具体:
    协程概念本质是程序员抽象出来的,操作系统根本不知道协程存在,也就说来了一个线程我自己遇到io 我自己线程内部直接切到自己的别的任务上了,
    也就是实现了单线程下效率最高.

    优点:
    自己控制切换要比操作系统切换快的多
    缺点:
    对比多线程
    自己要检测所有的io,但凡有一个阻塞整体都跟着阻塞.
    对比多进程
    无法利用多核优势.

    为什么要有协程(遇到io切换)?
    自己控制切换要比操作系统切换快的多.降低了单个线程的io时间,

    #计算状态下使用协程
    import time
    def func1():
    while True:
    1000000+1
    yield

    def func2():
    g = func1()
    for i in range(100000000):
    i+1
    next(g)

    start = time.time()
    func2()
    stop = time.time()
    print(stop - start) # 14.774465560913086


    # 对比通过yeild切换运行的时间反而比串行更消耗时间,这样实现的携程是没有意义的。
    import time
    def func1():
    for i in range(100000000):
    i+1
    def func2():
    for i in range(100000000):
    i+1

    start = time.time()
    func1()
    func2()
    stop = time.time()
    print(stop - start) # 8.630893230438232

    #io情况下使用协程
    from gevent import monkey;monkey.patch_all() #打了一个补丁,可以实现捕获非gevent的io.
    import gevent

    import time
    def eat():
    print('eat 1')
    time.sleep(2)
    print('eat 2')
    def play():
    print('play 1')
    # 疯狂的计算呢没有io
    time.sleep(3)
    print('play 2')

    start = time.time()
    g1 = gevent.spawn(eat)
    g2 = gevent.spawn(play)
    g1.join()
    g2.join()
    end = time.time()
    print(end-start) # 3.0040290355682373



    用多线程来写socket服务端与客户端
    #服务端
    import socket
    from threading import Thread


    def talk(conn):
    while True:
    try:
    msg=conn.recv(1024)
    if len(msg) == 0:break
    conn.send(msg.upper())
    except ConnectionResetError:
    print('客户端关闭了一个链接')
    break
    conn.close()

    def sever_demo():
    server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind(('127.0.0.1',8081))
    server.listen(5)

    while True:
    conn,addr=server.accept()
    t = Thread(target=talk,args=(conn,))
    t.start()

    if __name__ == '__main__':
    sever_demo()

    #客户端
    import socket
    from threading import Thread,currentThread

    def client_demo():
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    client.connect(('127.0.0.1',8081))
    while True:
    msg = f'{currentThread().name}'
    if len(msg) == 0: continue
    client.send(msg.encode('utf-8'))
    feedback = client.recv(1024)
    print(feedback.decode('utf-8'))

    client.close()

    if __name__ == '__main__':
    for i in range(20):
    t = Thread(target=client_demo)
    t.start()

     


     
  • 相关阅读:
    Countly在andoid和vps集成使用,开源的统计分析sdk
    简单dp-poj-2231-Moo Volume
    Head First设计模式-观察者模式
    D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建
    面试之BI-SQL--table转换[2]
    oracle表数据误删还原
    SQL Server 2008数据库创建,备份,还原图解及注意点
    SHH入门:Spring框架简介
    基于总变差模型的纹理图像中图像主结构的提取方法。
    windows程序员进阶系列:《软件调试》之堆 (一)
  • 原文地址:https://www.cnblogs.com/wwei4332/p/11550293.html
Copyright © 2020-2023  润新知