• python-线程协程网络编程


    1、线程、

    线程共享的不安全性

    '''
    线程共享数据的不安全性
    '''
    import time
    from threading import Thread, current_thread, Lock
    
    ticket = 10
    
    
    def sale_ticket(lock):
        global ticket
        while True:
    
            if ticket > 0:
                lock.acquire()
                print('{}正在卖第{}张票'.format(current_thread().name, ticket))
                ticket -= 1
                lock.release()
                time.sleep(1)
            else:
                print('票卖光啦!')
                # lock.release()
                break
    
    
    if __name__ == '__main__':
        lock = Lock()
        t1 = Thread(target=sale_ticket, name='1号窗口', args=(lock,))
        t2 = Thread(target=sale_ticket, name='2号窗口', args=(lock,))
        t3 = Thread(target=sale_ticket, name='3号窗口', args=(lock,))
        t4 = Thread(target=sale_ticket, name='4号窗口', args=(lock,))
    
        t4.start()
        t1.start()
        t2.start()
        t3.start()
    View Code

    死锁:两把锁

    申请锁的顺序使用不当

    开发过程中使用线程,在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,尽管死锁很少发生,但一旦发生就会造成应用的停止响应,程序不做任何事情

    避免死锁:

    1、重构代码  2、使用timeout参数

    import time
    from threading import Lock, Thread, current_thread
    
    
    def task1(lock1, lock2):
        if lock1.acquire():
            print('{}获取到lock1锁。。。。'.format(current_thread().name))
            for i in range(5):
                print('{}------------------>{}'.format(current_thread().name, i))
                time.sleep(0.01)
            if lock2.acquire(timeout=2):
                print('{}获取了lock1,lock2'.format(current_thread().name))
                lock2.release()
    
            lock1.release()
    
    
    def task2(lock1, lock2):
        if lock2.acquire():
            print('{}获取到lock2锁。。。。'.format(current_thread().name))
            for i in range(5):
                print('{}----->{}'.format(current_thread().name, i))
                time.sleep(0.01)
            if lock1.acquire(timeout=2):
                print('{}获取了lock1,lock2'.format(current_thread().name))
                lock1.release()
            lock2.release()
    
    
    if __name__ == '__main__':
        lock1 = Lock()
        lock2 = Lock()
    
        t1 = Thread(target=task1, args=(lock1, lock2))
        t2 = Thread(target=task2, args=(lock1, lock2))
    
        t1.start()
        t2.start()
    View Code

    线程同步: 

    同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
    "同"字从字面上容易理解为一起动作
    其实不是,"同"字应是指协同、协助、互相配合。
    如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。

    线程异步:
    在没有共享数据的情况下使用,效率高

    进程线程的区别:
    定义的不同
    进程是系统进行资源分配和调度的一个独立单位.
    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

    区别
    一个程序至少有一个进程,一个进程至少有一个线程.
    线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
    进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
    线线程不能够独立执行,必须依存在进程中

    优缺点
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。

    2、线程的信号量

    信号量的实现方式:
    在内部有一个counter计数器,每当我们 s.acquire()一次,计数器就进行减1处理
    每当 s.release()一次,计数器就进行加1处理,当计数器为0的时候其他线程的就处于
    等待的状态counter的值就是同一时间可以开启线程的个数
    建议使用with

    import time
    from threading import Thread, Semaphore, current_thread
    
    
    # from multiprocessing import Semaphore,Process
    
    def task(s):
        s.acquire()  # 减1
        with s:
            for i in range(5):
                print('{}扫地....{}'.format(current_thread().name, i))
                time.sleep(1)
        s.release()  # 加1
    
    
    if __name__ == '__main__':
        s = Semaphore(4)
        for i in range(10):
            t = Thread(target=task, args=(s,))
            t.start()
    View Code

     3、协程:伪线程

    实现交替执行

    def eat():
        for i in range(5):
            print('gang welcome you')
            yield
    
    def listen():
        for i in range(5):
            print('yinxing de chi bang')
            yield
    
    if __name__ == '__main__':
        a1 = eat()
        a2 = listen()
        while True:
            try:
                next(a1)
                next(a2)
            except:
                break
    使用生成器

    greenlet

    '''
     greenlet
     gevent
    
    '''
    from greenlet import greenlet
    
    
    def eat():
        for i in range(5):
            print('坤坤喜欢吃肉饼...')
            g2.switch()
    
    def listen_music():
        for i in range(5):
            print('坤坤喜欢听麻婆豆腐..', i)
            g1.switch()
    
    
    if __name__ == '__main__':
        g1 = greenlet(eat)
        g2 = greenlet(listen_music)
    
        g1.switch()
    View Code

    gevent:使用猴子补丁实现交替执行(给耗时的操作贴上标签)

    import time
    
    import gevent
    from gevent import monkey
    
    monkey.patch_all()
    
    def eat():
        for i in range(5):
            print('gang welcome you')
            time.sleep(0.1)
    
    
    def listen():
        for i in range(5):
            print('yinxing de chi bang')
            time.sleep(0.1)
    
    
    if __name__ == '__main__':
        g1 = gevent.spawn(eat)
        g2 = gevent.spawn(listen)
    
        g1.join()
        g2.join()
    
        print('over...')
    View Code

    网络编程

    TCP是建立可靠的连接,并且通信双方都可以以流的形式发送数据。

    UDP则是面向无连接的协议。使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发送数据包。但是能不能到达就不知道了。

     端口号:理解成端口号,识别应用

    netstat -an  查看端口的使用

    IP地址:电脑在互联网的标识

    socket(简称:套接字)
    它是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
    它能实现不同带闹闹见的进程间通信,我们网络上各种各种各样的服务大多都是
    基于Socket 来完成通信的

    参数一:指定协议 AF_INET  或AF_INRT6

    参数二:SOCK_STREAM执行使用面向流的TCP协议

    from socket import socket,AF_INET,SOCK_STREAM
    
    # 创建了一个客户端的socket
    client = socket(AF_INET,SOCK_STREAM)
    
    conn_address = ('10.0.102.132',9001)
    
    # 告诉客户端要连接的服务器的地址和端口号
    client.connect(conn_address)
    
    client.send('gang要来了!!!'.encode('utf-8'))
    
    client.close()
    客户端
    '''
    创建一个socket服务器
    
    '''
    from socket import socket, AF_INET, SOCK_STREAM
    
    # 创建socket对象
    server = socket(AF_INET, SOCK_STREAM)
    # 绑定端口号
    server.bind(('', 9001))
    
    # 开启监听状态  监听:
    server.listen(5)
    
    while True:
        socket, addr_info = server.accept()  # 阻塞的
        # print(socket, addr_info)
        data = socket.recv(512).decode('utf-8')
    
        print('{}发过来的消息式:{}'.format(addr_info[0],data))
        socket.close()
        print(addr_info, '离开了')
    服务端

     另一种方式:

    from socket import socket, AF_INET, SOCK_STREAM
    
    # 创建了一个客户端的socket
    client = socket(AF_INET, SOCK_STREAM)
    
    conn_address = ('10.0.102.144', 9001)
    
    # 告诉客户端要连接的服务器的地址和端口号
    client.connect(conn_address)
    
    while True:
        msg = input('客户端输入:')
        client.send(msg.encode('utf-8'))
    
        if msg == '88':
            break
        # 接收信息
        recv_msg = client.recv(512).decode('utf-8')
        print('服务器会话:', recv_msg)
        if recv_msg == '88':
            break
    
    client.close()
    客户端
    from socket import socket, AF_INET, SOCK_STREAM
    
    # 创建socket对象
    server = socket(AF_INET, SOCK_STREAM)
    # 绑定端口号
    server.bind(('', 9001))
    
    # 开启监听状态  监听:
    server.listen(5)
    
    while True:
        socket, addr_info = server.accept()  # 阻塞的
        # print(socket, addr_info)
        while True:
            data = socket.recv(512).decode('utf-8')
            print('客户端说:{}'.format(data))
            if data=='88':
                break
            msg = input('服务器输入:')
            socket.send(msg.encode('utf-8'))
            if msg =='88':
                break
        socket.close()
        print(addr_info, '离开了')
    服务端

    方式三:

    客户端
    from socket import socket, AF_INET, SOCK_STREAM
    
    # 创建了一个客户端的socket
    from threading import Thread
    
    client = socket(AF_INET, SOCK_STREAM)
    
    conn_address = ('10.0.102.144', 9002)
    
    # 告诉客户端要连接的服务器的地址和端口号
    client.connect(conn_address)
    
    
    # 任务
    def send_msg(sock):
        while True:
            msg = input('输入要发送的消息:')
            sock.send(msg.encode('utf-8'))
    
    
    def recv_msg(sock):
        while True:
            data = sock.recv(512).decode('utf-8')
            if len(data) == 0:
                break
            print('
    收到了服务器端的消息:', data)
    
    
    Thread(target=send_msg, args=(client,)).start()
    Thread(target=recv_msg, args=(client,)).start()
    
    # client.close()

    from socket import socket, AF_INET, SOCK_STREAM
    from threading import Thread
    
    # 创建socket对象
    server = socket(AF_INET, SOCK_STREAM)
    # 绑定端口号
    server.bind(('', 9002))
    
    # 开启监听状态  监听:
    server.listen(5)
    
    
    # 任务
    def send_msg(sock):
        while True:
            msg = input('输入要发送的消息:')
            sock.send(msg.encode('utf-8'))
    
    
    def recv_msg(sock):
        while True:
            data = sock.recv(512).decode('utf-8')
            if len(data) == 0:
                break
            print('
    收到了客户端的消息:', data)
    
    
    while True:
        sock, addr_info = server.accept()  # 阻塞的
        t1 = Thread(target=send_msg, args=(sock,))
        t2 = Thread(target=recv_msg, args=(sock,))
    
        t1.start()
        t2.start()
        # sock.close()
        print(addr_info, '离开了')
    服务端

    浏览器服务端模式:

    '''
    client:浏览器客户端
    server端:
    
    浏览器请求:
    server端响应
    
    '''
    
    from gevent import monkey,socket
    # 创建socket对象
    monkey.patch_all()
    import gevent
    server = socket.socket()
    # 绑定端口号
    server.bind(('', 9001))
    
    # 开启监听状态  监听:
    server.listen(5)
    
    
    def handle_client(sock):
        print('--------------')
        recv_data = sock.recv(1024).decode('utf-8')
        print(recv_data)
    
        res_line = 'HTTP/1.1 200 OK
    '
        res_header = 'Content-Type:text/html;charset=utf-8
    Server:Apache
    '
        msg = '<h1>你回去吧!!!</h1>'
        response = res_line+res_header+'
    '+msg
    
        sock.send(response.encode('utf-8'))
        sock.close()
    
    
    while True:
        sock, addr_info = server.accept()  # 阻塞的
        print(addr_info,'来了')
        gevent.spawn(handle_client,sock)
    服务端
    # __author:gang
    # date:  2019/8/15
    # coding = utf-8
    import socket
    from multiprocessing import Process
    import re
    
    # 常量名字大写
    HTML_ROOT_DIR = './html'
    
    
    class HttpServer(object):
        def __init__(self):
            # 创建TCP服务端
            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # 服务端口可以重复启动,不会被占用
            self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
        def bind(self, port1):
            # 绑定端口
            self.server.bind(('', port1))
    
        def start(self):
            # 设置监听
            self.server.listen(128)
            while True:
                client_socket, client_address = self.server.accept()
                client = Process(target=self.handle_client, args=(client_socket,))
                client.start()
                # 在主进程中关闭连接
                client_socket.close()
    
        def handle_client(self, client_socket):
            # 获取客户端请求的数据
            request_data = client_socket.recv(1024)
            request_lines = request_data.splitlines()
            for line in request_lines:
                print(line)
            request_start_line = request_lines[0].decode('utf-8')
            # 使用正则表达式,得到请求的路径或者index.html
            file_path = re.match(r'w+ +(/[^ ]*)', request_start_line)
            file_name = file_path.group(1)
            print('file_name:', file_name)
            if '/' == file_name:
                file_name = '/index.html'
            try:
                # 打开文件读取/html/index.html文件内容,以二进制方式
                f = open(HTML_ROOT_DIR + file_name, 'rb')
            except:
                # 构造相应数据
                response_start_line = "HTTP/1.1 404 Not Found File
    "
                response_headers = "Server:My Server
    "
                response_body = "sorry!file not found!"
            else:
                # 文件存在,正常处理
                file_data = f.read()
                # 关闭文件
                f.close()
                # 构造相应数据
                response_start_line = "HTTP/1.1 200 OK
    "
                response_headers = "Server:My Server
    "
                response_body = file_data.decode("utf-8")
    
                # 拼接数据:注意响应头和响应体要加上
    
            response = response_start_line + response_headers + "
    " + response_body
            print("response data:", response)
            # client_socket.send(bytes(response,"utf-8"))
            client_socket.send(response.encode("utf-8"))
            client_socket.close()
    
    
    def main():
        http_server = HttpServer()
        http_server.bind(7788)
        http_server.start()
    
    
    if __name__ == '__main__':
        main()
    用进程实现

    匹配网页的正则表达式 

    pat = r'(((http|ftp|https)://)(([a-zA-Z0-9._-]+.[a-zA-Z]{2,6})|([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9&%_./-~-]*)?)'
    一路独行,遇见最好的自己!!!
  • 相关阅读:
    Android 编辑框(EditText)属性学习
    读书笔记 -《高效程序猿的45个习惯-敏捷开发修炼之道》
    Launcher3实现壁纸居中
    Trie树的常见应用大总结(面试+附代码实现)
    LeetCode Summary Ranges
    abap选择屏幕上的button
    SQLite Expert表分离和解决SQLite Expert删除表后大小不变的问题
    git push 失败
    动态限制EdiText仅仅能输入特定字符
    DateTime类常用技巧摘录
  • 原文地址:https://www.cnblogs.com/rungang/p/11360554.html
Copyright © 2020-2023  润新知