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)
    

      

  • 相关阅读:
    iOS 6 Tutorials
    iPhone:文本设计的注意事项
    Beginning Storyboards in iOS 5 Part 2
    代友招聘一名网站开发人员
    利用反射自己写的一个ModelHelper类
    SQL中 对逻辑值取反赋值的语句
    记点uml的表现方式
    我的2008年
    Framework 4.0 新关键字dynamic 之我见(一)
    我的采集小程序配置篇
  • 原文地址:https://www.cnblogs.com/csic716/p/12011548.html
Copyright © 2011-2022 走看看