千锋的第十八天

一、多线程技术1

python内置的threading模块,可以支持多线程

所有的进程默认都有一个线程(一般叫这个线程为主线程)
如果想要在进程中添加其他线程,就创建线程对象

from threading import Thread
import time
def download(file):
    print('开始下载',file)
    time.sleep(5)
    print(file,'下载结束')

print('======')
t1 = Thread(target=download, args=['天下无贼'])
t1.start()

t2 = Thread(target=download, args=['十面埋伏'])
t2.start()

print("It's ok now")

# 总结:在主线程中开启一个支线程,需要先建立一个支线程
# 方式:t1 = Thread(target=函数名,args=参数列表)  或者t1 = threading.Thread(target=函数名,args=参数列表)  t1 代表了一个支线程的名字
# 支线程要通过t1.start()函数来调用才能开始运行
结果;======
开始下载 天下无贼
开始下载 十面埋伏
It's ok now
十面埋伏 下载结束
天下无贼 下载结束

二、多线程技术2

方式2:写一个线程类
1.写一个类,继承自Thread类
2.重写run,在里面规定需要在子线程中执行的内容
3.实现在子线程中执行的任务对应的功能,如果需要参数,通过类的对象的属性来传值

from threading import Thread
import time
class Download(Thread):                 #该类继承自Thread,因此拥有Thread的一切方法
    def __init__(self, file_name):      #因为要添加属性,所以要继承父类的对象属性,不然的话就是再重写对象属性
        super().__init__()
        self.name = file_name
    def run(self):                      #如果方法用需要使用到参数,则需要在属性里面声明
        print('开始下载', self.name)
        time.sleep(5)
        print(self.name, '下载完毕')


t1 = Download('天下无贼')    #这是在建立一个Download对象
t1.start()                  #通过对象调用方法,只不过这里是固定的用start()函数可以调用run方法
# t1.run()                  #直接用对象调用run方法是在主程序中执行,如果用start()函数调用,就是在支线程里面执行

t2 = Download('阿凡达')
t2.start()

print('=======')

三、多线程的应用

实现服务器可以同时接入多个客户端

import socket
from threading import Thread

class ConversationThread(Thread):
    """在子线程中处理不同的客户端会话"""
    """
    python可以在函数参数的后面加一个冒号(:),来对参数的类型进行说明,并不影响传值
    
    """
    def __init__(self, conversation, address):
        super().__init__()
        self.conversation = conversation
        self.address = address

    def run(self):
        while True:
            message = input('输入你想说的话:')
            self.conversation.send(message.encode(encoding='utf-8'))
            print(self.address,self.conversation.recv(1024).decode(encoding='utf-8'))


if __name__ == '__main__':
    server = socket.socket()

    server.bind(('10.7.181.112', 10000))

    server.listen(500)          #在监听时候,只要有人接入   while循环就会返回conversation和address

    while True:

        conversation, address = server.accept()         #accept会阻塞线程等待

        t = ConversationThread(conversation, address)
        t.start()

如果一个任务想要在另外一个子线程中的结束完成后再执行就在当前任务前用子线程对象调用join方法
join也会阻塞线程,阻塞到对应的子线程中的任务执行完为止,如果有一部分操作
想被阻塞,就放在join前面
如果有一部分操作需要在某个子线程结束之后执行,就写在join后面

四、多线程原理

进程:系统中一个正在运行的应用程序(只有在运行的程序才是进程),只有在运行的程序,才会开辟空间去储存它
在不使用的情况下,程序是保存在硬盘中的,只有在运行的时候,内存才会开辟空间去储存正在被执行的程序,这时候程序就
变成了一个进程

什么是线程:一个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程)
一个进程(程序)的所有任务都在线程中执行,线程是执行进程的一个基本单元

单线程: 1个线程中任务的执行时串行的(串行:一串的执行,也就是一个一个的执行,从上到下执行)

多线程: 1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务
进程--->车间 线程----->车间工人

多线程技术可以提高程序的执行效率

单线程就是一个人干活,多线程就是多个人同时干活
总结:单线程串行,多线程并行

多线程的原理:
同一时间,CPU只能处理一条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发的假象

作业

# 创建一个服务器,可以实现双向聊天功能,当对方输入文字以后可以将文字在pygame中的屏幕上从上到下展示出来
import socket
import pygame
from threading import Thread
import time
def showfont(data):
    pygame.init()
    screen = pygame.display.set_mode((600, 400))
    screen.fill((255, 255, 255))
    x = 0
    y = 200
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit()
        screen.fill((255, 255, 255))
        font = pygame.font.SysFont("simsunnsimsun", 40)
        surface = font.render(data, True, (0, 0, 0))
        screen.blit(surface, (x, y))
        pygame.display.flip()
        time.sleep(0.02)
        x += 2

class ClientThread(Thread):
    def __init__(self, client):
        super().__init__()
        self.client = client

    def run(self):
        while True:
            send_message = input('请输入你想发送的内容:')
            self.client.send(send_message.encode(encoding='utf-8'))

            data = self.client.recv(1024).decode(encoding= 'utf-8')
            showfont(data)


server = socket.socket()
server.bind(('10.7.181.112', 10000))
server.listen(520)

while True:
    client, address = server.accept()
    t1 = ClientThread(client)
    t1.start()

你可能感兴趣的:(千锋的第十八天)