zoukankan      html  css  js  c++  java
  • CSIC_716_20191209【并发编程---GIL和协程】

    GIL   Global Interpreter Lock 全局解释锁

    GIL对含IO的任务来说,会出现不能保证数据安全的情况。如下:

    from threading import Thread
    from threading import Lock
    import time
    n = 100
    def task1():
        global n
        m = n
        time.sleep(0.1)
        n = m + 1
    if __name__ == '__main__':
        lock = Lock()
        list1 = []
        for line in range(5):
            t1 = Thread(target=task1)
        t1.start()
        list1.append(t1)
        for i in list1:
            t1.join()
        print(n)
    

      打印的值为101,因为在线程遇到IO时,会被剥夺CPU执行权限,当IO结束时,不同线程的均取到最初的n值。

    ********************************************************************************************************************************

    含有IO的涉及修改数据的任务,要加上线程互斥锁

    from threading import Thread
    from threading import Lock
    import time
    
    n = 100
    def task1():
        global n
        lock.acquire()
        m = n
        time.sleep(1)
        n = m + 1
        lock.release()
    if __name__ == '__main__':
        lock = Lock()
        list1 = []
        for line in range(5):
            t1 = Thread(target=task1)
            t1.start()
        list1.append(t1)
        for i in list1:
            t1.join()
        print(n)  

    结果为105,加了锁,将并发编程串行。

    ********************************************************************************************************************************

    GIL对不含IO的任务来说,可以保证数据安全的情况。如下:

    n = 100
    def task1():
        global n
        m = n
        n = m + 1
    if __name__ == '__main__':
        lock = Lock()
        list1 = []
        for line in range(5):
            t1 = Thread(target=task1)
            t1.start()
        list1.append(t1)
        for i in list1:
            t1.join()
        print(n)
    

      结果为105,全局锁起到了线程锁的效果。

    ********************************************************************************************************************************

    协程

    协程用于在单线程下实现并发。

    协程对IO密集型很有用,感觉是为了最大化利用操作系统分配给进程的时间片。

    协程是手动实现IO切换+保存状态,去欺骗操作系统,让操作系统误以为没有发生IO。

    使用第三方模块 gevent

    # _*_ coding: gbk _*_
    # @Author: Wonder
    from gevent import monkey  # monkey.patch_all 猴子补丁
    from gevent import spawn  # spawn() ,用于创建协程
    from gevent import joinall  # joinall[spawn1,spawn2,spawn3]
    import time
    
    monkey.patch_all()
    
    def task1():
        print('start......')
        time.sleep(1)
        print('end......')
    
    def task2():
        print('start......')
        time.sleep(1)
        print('end......')
    
    if __name__ == '__main__':
        sp1 = spawn(task1)
        sp2 = spawn(task2)
        joinall([sp1, sp2])   # 将join合并起来了,等到协程结束,再结束线程
    

      

    monkey.patch_all( ),监听所有的任务是否有IO操作,并将IO转为gevent能识别的IO,一定要写在最前面,导入时就写。

    spawn()提交协程 ,内部做了start()

    joinall( [ sp1 ,  sp2 , ....] )  将等待sp1,sp2协程结束

    网络编程+并发编程   实例

    SOCKET套接字通信,Server端用协程并发处理Client端用线程并发访问

    SERVER 服务端

    # _*_ coding: gbk _*_
    # @Author: Wonder
    import socket
    from gevent import monkey
    from gevent import spawn
    
    monkey.patch_all()
    
    
    def server(ip, port):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((ip, port))
        server.listen(5)
        while True:
            conn, addr = server.accept()
            spawn(run, conn)  # 协程
    
    
    def run(conn):
        while True:
            try:
                data = conn.recv(1024)
                if not data:
                    break
                print(data.decode('utf-8'))
                conn.send('永不在线'.encode('utf-8'))
            except Exception as e:
                print(e)
                break
        conn.close()
    
    
    if __name__ == '__main__':
        p1 = spawn(server, '127.0.0.1', 9527)  # 协程
        p1.join()
    

      

    Client 客户端

    # _*_ coding: gbk _*_
    # @Author: Wonder
    import socket
    from concurrent.futures import ThreadPoolExecutor
    from threading import current_thread
    
    
    def client(i):
        cliet = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        cliet.connect(
            ('127.0.0.1', 9527)
        )
        while True:
            cliet.send(('NO_%s;线程号:%s' % (i, current_thread().getName())).encode('utf-8'))
            data = cliet.recv(1024)
            print(data.decode('utf-8'))
    
    
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(5)
        for i in range(100):
            pool.submit(client, i)
    

      

  • 相关阅读:
    strict aliasing
    加密数据包加解密部分逆向跟踪
    自定义session扫描器
    同步容器类ConcurrentHashMap及CopyOnWriteArrayList
    CountDownLatch闭锁
    volatile关键字与内存可见性
    原子变量与CAS算法
    C语言笔记一
    小组讨论4
    201920201学期 20192416《网络空间安全专业导论》第六周学习总结
  • 原文地址:https://www.cnblogs.com/csic716/p/12011548.html
Copyright © 2011-2022 走看看