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()
死锁:两把锁
申请锁的顺序使用不当
开发过程中使用线程,在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,尽管死锁很少发生,但一旦发生就会造成应用的停止响应,程序不做任何事情
避免死锁:
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()
线程同步:
同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
"同"字从字面上容易理解为一起动作
其实不是,"同"字应是指协同、协助、互相配合。
如进程、线程同步,可理解为进程或线程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()
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
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...')
网络编程
端口号:理解成端口号,识别应用
netstat -an 查看端口的使用
IP地址:电脑在互联网的标识
socket(简称:套接字)
它是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同带闹闹见的进程间通信,我们网络上各种各种各样的服务大多都是
基于Socket 来完成通信的:

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()
