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('\n收到了服务器端的消息:', 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('\n收到了客户端的消息:', 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\r\n'
    res_header = 'Content-Type:text/html;charset=utf-8\r\nServer:Apache\r\n'
    msg = '<h1>你回去吧!!!</h1>'
    response = res_line+res_header+'\r\n'+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\r\n"
            response_headers = "Server:My Server\r\n"
            response_body = "sorry!file not found!"
        else:
            # 文件存在,正常处理
            file_data = f.read()
            # 关闭文件
            f.close()
            # 构造相应数据
            response_start_line = "HTTP/1.1 200 OK\r\n"
            response_headers = "Server:My Server\r\n"
            response_body = file_data.decode("utf-8")

            # 拼接数据:注意响应头和响应体要加上\r\n
        response = response_start_line + response_headers + "\r\n" + 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\&%_\./-~-]*)?)'

 

posted @ 2019-08-15 21:06  刚--  阅读(179)  评论(0编辑  收藏  举报