线程:进程中负责程序执行的执行单元。
多线程:在1个进程中存在多个线程。
进程只是用来把资源集中在一起,而线程才是cpu上的执行单位。
每个进程都会默认有一个控制线程也叫作主线程。
进程之间是竞争关系,线程之间是协作关系。
多线程和进程之间的区别?
1.线程开销小,不需要申请内存空间,创建速度快。进程需要申请内存空间,创建速度慢。
2,同一进程下的多个线程,共享该进程的地址空间。
3,改变主进程 ,无法影响子进程,改变了主线程,影响其他线程。原因(该控制线程可以执行代码从而创建新的线程,该主线程的运行周期代表了进程的运行周期)
如何开启子线程?有两种方法。
方法一:创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入。(这个方法是重点)
方法二:通过继承Thread类,重写它的run方法;(这个方法作为了解)
方法一:
from threading import Threadimport time ,os def task(): print("%s is runing"%os.getpid()) time.sleep(2) print("%s is done"%os.getpid()) if __name__=="__main__": t=Thread(target=task) t.start() print("主") #主线程运行周期代表进程的运行周期,他不能先死,他要等子线程运行完和进程意义不同
15640 is runing 主
15640 is runing
方法二:
from threading import Thread import os class My_task(Thread): def __init__(self,name): super(My_task,self).__init__() self.name=name def run(self): print("%s is runing" % os.getpid()) time.sleep(2) print("%s is done"%os.getpid()) if __name__ == '__main__': t=My_task("小红") t.start() print(t.name)
结果:
24156 is runing 小红 24156 is done
子进程不能修改主进程的变量,子线程能修改主线程的变量
范例:
n=1 def t(): global n n=15 if __name__ == '__main__': t=Thread(target=t) t.start() print(n)
结果:
15
线程主要掌握的方法有3个 :
start(),
join()
from threading import current_thread , 中有个叫current_thread .getName()这个可以看线程的名字
线程池:如果你不指定默认是CPU的个数*5,进程池如果你不指定默认是CPU的个数。
from concurrent.futures import ThreadPoolExecutor from threading import current_thread import time ,random def task(n): print("%s is running"%current_thread().getName()) time.sleep(random.randint(1,3)) return n**2 if __name__ == '__main__': t=ThreadPoolExecutor(3) objs=[] for i in range(10): obj=t.submit(task,i) objs.append(obj) t.shutdown(wait=True) for obj in objs: print(obj.result()) print("主",current_thread().getName())
结果:
ThreadPoolExecutor-0_0 is running ThreadPoolExecutor-0_1 is running ThreadPoolExecutor-0_2 is running ThreadPoolExecutor-0_1 is running ThreadPoolExecutor-0_2 is running ThreadPoolExecutor-0_0 is running ThreadPoolExecutor-0_2 is running ThreadPoolExecutor-0_0 is running ThreadPoolExecutor-0_1 is running ThreadPoolExecutor-0_0 is running 0 1 4 9 16 25 36 49 64 81 主 MainThread
异步调用:提交完任务(为该任务绑定一个回调函数),不用在原地等任务执行完拿结果,可以直接提交下一个任务。一个任务一旦完成后就会立即触发回调函数的运行。
回调函数的参数是唯一的就是它绑定的返回值。
利用多线程来重写套接字
服务端:
from threading import Thread import socket import socketserver server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(("192.168.12.193",8085)) server.listen(5) print("starting") def talk(conn,addr): """ 接收数据发送数据函数 :param conn: :param addr: :return: """ while True: try: data=conn.recv(1024) if not data:break conn.send(data.upper()) except ConnectionResetError: break conn.close() while True: conn,addr=server.accept() t=Thread(target=talk,args=(conn,addr)) t.start() server.close()
客户端:
import socket custom=socket.socket() custom.connect(("127.0.0.1",8080)) while True: msg=input(">>>>").strip() if not msg: continue custom.send(msg.encode("utf-8")) data=custom.recv(1024) print(data.decode("utf-8")) custom.close()
socketserver模块
这个模块提供了多进程和多线程的接口,但是多进程不能在Windows系统下用
利用aocketserver模块来重写多线程的套接字服务端
class MyTCPhandler(socketserver.BaseRequestHandler): def handle(self): conn=self.request #这步相当于conn addr=self.client_address #这步相当于addr print(conn,addr) while True: try: data=conn.recv(1024) if not data:break conn.send(data.upper()) except ConnectionResetError: break conn.close() if __name__ == '__main__': server=socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyTCPhandler) #这一步就是做了,建立连接,开线程的工作 注意在Windows系统上不能用socketserver来开线程,在其他系统上可以用socketserver.ForkingTCPServer(("127.0.0.1",8080),MyTCPhandler)来创建
server.allow_reuse_address=True
server.serve_forever()