多任务简单地说,就是操做系统能够同时运行多个任务。分为并行和并发两种。python
指的是任务数小于等于CPU核数,即任务真的是一块儿执行的算法
指的是任务数多于CPU核数,经过操做系统的各类任务调度算法,实现用多个任务一块儿执行(实际上总有一些任务不在执行,由于切换任务的速度至关快,看上去一块儿执行而已)浏览器
网络就是辅助双方或多方,链接在一块儿的辅助工具服务器
网络可以实现数据的相互传送,可以通讯,互相传递信息等。网络
ip地址就是在网络中标记一台计算机的地址,好比192.168.1.1;在本地局域网上是惟一的。多线程
是属于私网IP,不在公网中使用的,它们的范围是:并发
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
复制代码
IP地址127.0.0.1~127.255.255.255用于回路测试,app
如:127.0.0.1能够表明本机IP地址,用http://127.0.0.1就能够测试本机中配置的Web服务器。socket
端口号就是电脑上某个程序对应的地址,用来标记某个程序,端口号只有整数,范围是从0到65535async
socket是一种进程之间的通讯方式,简称套接字。它能实现不一样主机间的进程间通讯,咱们网络上各类各样的服务大多都是基于 Socket 来完成通讯的
例如咱们天天浏览网页、QQ 聊天、收发 email 等等。
import socket
socket.socket(AddressFamily, Type)
复制代码
说明:
函数 socket.socket 建立一个 socket,该函数带有两个参数:
Address Family:能够选择 AF_INET(用于 Internet 进程间通讯) 或者 AF_UNIX(用于同一台机器进程间通讯),实际工做中经常使用AF_INET Type:套接字类型,能够是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
python的thread模块是比较底层的模块,python的threading模块是对thread作了一些包装的,能够更加方便的被使用
#coding=utf-8
import threading
import time
def saySorry():
print("我能吃饭了吗?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=saySorry)
t.start() #启动线程,即让线程开始执行
复制代码
python的threading.Thread类有一个run方法,用于定义线程的功能函数,能够在本身的线程类中覆盖该方法。而建立本身的线程实例后,经过Thread类的start方法,能够启动该线程,交给python虚拟机进行调度,当该线程得到执行的机会时,就会调用run方法执行线程。
多线程程序的执行顺序是不肯定的。当执行到sleep语句时,线程将被阻塞,到sleep结束后,线程进入就绪状态,等待调度。而线程调度将自行选择一个线程执行。
当多个线程几乎同时修改某个共享数据的时候,须要进行同步控制。
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其余线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其余的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操做,从而保证了多线程状况下数据的正确性。
threading模块中定义了Lock类,能够方便的处理锁定:
# 建立锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
复制代码
在线程键共享多个资源的时候,若是两个线程分别占有一部分资源而且同时等待对方的资源,就会形成死锁。
能够添加超时时间等,解决死锁
import socket
import threading
def send_msg(udp_socket):
"""获取键盘数据,并将其发送给对方"""
while True:
# 1. 从键盘输入数据
msg = input("\n请输入要发送的数据:")
# 2. 输入对方的ip地址
dest_ip = input("\n请输入对方的ip地址:")
# 3. 输入对方的port
dest_port = int(input("\n请输入对方的port:"))
# 4. 发送数据
udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))
def recv_msg(udp_socket):
"""接收数据并显示"""
while True:
# 1. 接收数据
recv_msg = udp_socket.recvfrom(1024)
# 2. 解码
recv_ip = recv_msg[1]
recv_msg = recv_msg[0].decode("utf-8")
# 3. 显示接收到的数据
print(">>>%s:%s" % (str(recv_ip), recv_msg))
def main():
# 1. 建立套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定本地信息
udp_socket.bind(("", 7890))
# 3. 建立一个子线程用来接收数据
t = threading.Thread(target=recv_msg, args=(udp_socket,))
t.start()
# 4. 让主线程用来检测键盘数据而且发送
send_msg(udp_socket)
if __name__ == "__main__":
main()
复制代码
multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来表明一个进程对象,这个对象能够理解为是一个独立的进程,能够执行另外的事情。
建立子进程时,只须要传入一个执行函数和函数的参数,建立一个Process实例,用start()方法启动
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
def run_proc():
"""子进程要执行的代码"""
print('子进程运行中,pid=%d...' % os.getpid()) # os.getpid获取当前进程的进程号
print('子进程将要结束...')
if __name__ == '__main__':
print('父进程pid: %d' % os.getpid()) # os.getpid获取当前进程的进程号
p = Process(target=run_proc)
p.start()
复制代码
Process([group [, target [, name [, args [, kwargs]]]]])
target:若是传递了函数的引用,能够任务这个子进程就执行这里的代码
args:给target指定的函数传递的参数,以元组的方式传递
kwargs:给target指定的函数传递命名参数
name:给进程设定一个名字,能够不设定
group:指定进程组,大多数状况下用不到 Process建立的实例对象的经常使用方法:
start():启动子进程实例(建立子进程)
is_alive():判断进程子进程是否还在活着
join([timeout]):是否等待子进程执行结束,或等待多少秒
terminate():无论任务是否完成,当即终止子进程
Process建立的实例对象的经常使用属性:
name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
pid:当前进程的pid(进程号)
进程之间不共享全局变量
当须要建立的子进程数量巨大时,就能够用到multiprocessing模块提供的Pool方法
进程是经过导入Queue,用Queue实现多进程之间的数据传递,Queue自己是一个消息队列程序。
除了可使用next()函数来唤醒生成器继续执行外,还可使用send()函数来唤醒来执行,使用send()函数的一个好处是能够在唤醒的同时向断点处传入一个附加数据
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
复制代码
运行结果
<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4
复制代码
3个greenlet是依次运行而不是交替运行,能够导入time,添加延时切换执行
Python中遇到recv、accept、等语句时,是默认阻塞的,即若是不设置一些条件时,程序会一直等待下去。
而非阻塞就是经过设置条件,把阻塞变为非阻塞,因此转变语法须要在阻塞以前设置
例:server_socket.setblocking(False)
复制代码
请求包括:请求头、请求体、请求行
响应包括:响应头、响应行、响应体
短链接就是创建链接、接收数据、关闭链接,每次只获取1次数据
长链接就是创建链接后,屡次请求,直到没有请求后关闭的链接
TCP通讯的整个过程
四次挥手:客户端调用close时,向服务器发送请求,服务器回应请求同时解堵塞,调用本身close后,再次向客户端发送close请求,此时客户端方会等待两个最大报文时间,等待接收服务器的请求(等待是为了不断网,断电等特殊状况),收到服务器的请求后,向服务器回应请求,服务器收到请求后关闭,4次挥手成功,双方关闭链接