线程进程协程

文章目录

  • 多线程
    • 线程的实现
      • 线程的两种实现方式
    • 多线程并发的问题
    • 多线程中的锁
    • 线程池
  • 进程
    • ==进程== 的实现用函数;
    • ==进程== 的实现用重写类方法:
    • 进程之间的通信
    • 进程中的锁
    • 进程池
  • 协程(未看懂)
    • 协程的实现
    • 协程函数的嵌套调用
    • 协程通信之队列

string有很多行时,只能用三引号。其他时候都可以用。

num = [int(i) for i in inputs.split()]
# input().split()读一行以空格分开的元素,然后用int()转为整数
#input是字符串 有很多个数的
#用户类
class User:
   def __init__(self,first_name,last_name):
       self.first_name = first_name
       self.last_name = last_name
   def describe_user(self):
        print(f"当前用户的firstname是{self.first_name},lastname是{self.last_name}")

user1 = User(input("请输入firstname"),input('请输入lastname')) #函数调用时还可以直接用input
user1.describe_user()

在一个类中调用另一个类

class Restaurant: #类名首字母大写
    def __init__(self,restaurant_name,cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
        self.number_served = 0  #就餐人数设置为0
    def people_num(self):
        print(f"当前已经有{self.number_served}个人在这里吃饭过")
    def set_number_served(self,number):
        '''修改就餐人数'''
        self.number_served = number
        self.people_num()	#在一个方法中调用另一个方法要用self.方法名()

子类继承父类的属性

class ElectricCar(Car):
    def __int__(self,make,model,year):
        """初始化父类的属性"""
        super().__init__(make,model,year)

初始化为空字符串,在后面的时候判断是否为空(但不是None),实现该参数的可选性

def get_formatted_place(City,Country,population=''):
    if population:
        formatted_place = f"{City} {Country}-{population}"
    else:
        formatted_name = f"{City} {Country}"
    return formatted_name

多线程

线程的实现

线程的两种实现方式

  1. 定义运行线程函数,使用线程构造函数直接实现
import threading
import time

def loop():
    '''新的线程执行的代码'''
    n = 0
    while n < 5:
        print(n)
        now_thread = threading.current_thread()  # current_thread 用于调用当前正在运行的线程名称
        print(f"当前正在运行的线程名称:{now_thread}")
        time.sleep(1)   #休眠1s
        n += 1

def use_thread():
    """ 使用线程来实现 """
    #创建实例对象
    t = threading.Thread(target=loop,name='loop_thread') #目标函数是loop()函数,线程运行的是loop()函数
    #启动线程
    t.start()
    #挂起线程
    t.join()

if __name__ == '__main__':
    now_thread = threading.current_thread() #current_thread 用于调用当前正在运行的线程名称
    print(f"当前正在运行的线程名称:{now_thread}")
    use_thread()
  1. 构造继承自threading.Thread 的类,用该类实现线程的运行
import threading
import time

class LoopThread(threading.Thread): #继承自threading.Thread的类
    n = 0
    def run(self):		#重写run方法
        while self.n < 5:
            now_thread = threading.current_thread()
            print(f"当前正在运行的线程名称:{now_thread}")
            time.sleep(1)
            self.n += 1


if __name__ == '__main__':
    t = LoopThread(name = 'LoopThread')
    now_thread = threading.current_thread()
    print(f"当前正在运行的线程名称:{now_thread}")
    t.start() #启动进程
    t.join()  #挂起进程

多线程并发的问题

import threading,time

#银行存款为balance
balance = 0

 def change(n):
     #现存后取,结果应该为0
     global balance  #在函数内部调用全局变量,需定义    global 变量名
     balance += n
     balance -= n
     print(f">>>>>>>>>>{n,balance}")

 def run_thread(n):
     for i in range(10000):
         change(n)      #线程中调用函数

 if __name__ == '__main__':
     t1 = threading.Thread(target=run_thread, args=(5,)) # args: 以元组的方式给任务传入参数
     #换句话说,线程t1将调用函数run_thread(5)来执行任务,将数字5作为参数传递给该函数。
     t2 = threading.Thread(target=run_thread, args=(8,)) # args: 以元组的方式给任务传入参数
     t1.start()
     t2.start()
     t1.join()
     t2.join()
     print(balance)

#银行存款为balance
balance = 0

def change(n):
    global balance
    now_thread = threading.current_thread()
    print(f"当前正在运行的线程名称:{now_thread}")
    balance += n
    now_thread = threading.current_thread()
    print(f"当前正在运行的线程名称:{now_thread}")
    balance -= n
    print(f"当前存取金额:{n},当前钱数{balance}")


class ChangeBalanceThread(threading.Thread):
    """改变银行余额的线程"""

    def __init__(self,num,*args,**kwargs): #num表示存入银行的钱数  *args用于收集任意数量的位置参数, **kwargs用于收集任意数量的关键字参数
        super().__init__(*args,**kwargs)
        self.num = num

    def run(self):
        for i in range(10000):
            change(self.num)

if __name__ =='__main__':
    now_thread = threading.current_thread()
    print(f"当前正在运行的线程名称:{now_thread}")
    t1 = ChangeBalanceThread(5)  #线程1
    t2 = ChangeBalanceThread(8) #线程2
    t1.start()    #启动线程
    t2.start()    #启动线程
    t1.join()   #挂起线程
    t2.join()   #挂起线程

多线程中的锁

线程的库是threading
引入time库是为了休眠一会儿
线程中的锁有threading.Loc() threading.RLock() threading.

#代码是 多线程并发问题 代码的改进
import threading,time

#银行存款为balance
balance = 0

#定义锁
my_lock = threading.Lock() 
#RLock锁
# my_lock = threading.RLock()
def change(n):
     #现存后取,结果应该为0
     #方法一
    # try:
    #      my_lock.acquire()  #获取锁,即上锁
    #      global balance  #在函数内部调用全局变量,需定义    global 变量名
    #      balance += n
    #      balance -= n
    #      print(f">>>>>>>>>>{n,balance}")
    # finally:
    #     my_lock.release()   #释放锁

    #方法二
    with my_lock:
        global balance
        balance += n
        balance -= n
        print(f">>>>>>>{n,balance}")
         
def run_thread(n):
    for i in range(10000):
        change(n)      #线程中调用函数

if __name__ == '__main__':
     t1 = threading.Thread(target=run_thread, args=(5,)) # args: 以元组的方式给任务传入参数
     t2 = threading.Thread(target=run_thread, args=(8,)) # args: 以元组的方式给任务传入参数
     t1.start()
     t2.start()
     t1.join()
     t2.join()
     print(balance)

线程池

import time
import threading
from concurrent.futures import ThreadPoolExecutor
from multiprocessing.dummy import Pool  		#进程中的线程池


def run(n):
    """ 线程要做的事情 """
    time.sleep(2)
    print(threading.current_thread().name, n)


def main():
    """ 使用传统的方法来做任务 """
    t1 = time.time()    #获取当前的时间
    for n in range(5):
        run(n)
    print(time.time() - t1)     #输出运行的时间


def main_use_thread():
    """ 使用线程优化任务 """
    # 假设资源有限,最多只能跑10个线程:
    t1 = time.time()    #获取当前时间
    ls = []
    for count in range(10): #跑10次,一次2s,一次10个线程并发执行。
        for i in range(10):     #创建10个线程,并发执行
            t = threading.Thread(target=run,args=(i,))
            ls.append(t)
            t.start()
        for l in ls:    #10个线程执行完之后,全部阻塞
            l.join()
    print(time.time() - t1)


def main_use_pool():
    """ 使用线程池来优化 """
    t1 = time.time()
    n_list = range(100)
    pool = Pool(10)     #创建了一个具有10个线程的线程池
    pool.map(run,n_list)    #n_list中的每个元素作为run的参数 映射关系
    pool.close()        #关闭线程池
    pool.join()         #等待所有任务执行完成后阻塞
    print(time.time() - t1)


#用另一种线程池来实现
def main_use_executor():
    """ 使用ThreadPoolExecutor """
    t1 = time.time()
    n_list = range(100)
    with ThreadPoolExecutor(max_workers=10) as executor:
        executor.map(run,n_list)
    print(time.time() - t1)


if __name__ == '__main__':
    #main()
    #main_use_thread()
    #main_use_pool()
    main_use_executor()

进程

使用multiprocessing实现多进程代码
使用multiprocessing.Process创建进程
start()启动进程
join()挂起进程
import os os.getpid()获取进程id

进程 的实现用函数;

import os #用于得到进程的pid
import time
from multiprocessing import Process


def do_sth(name):
    """
    :param name: str 表示进程的名称
    """
    print(f"进程的名称为{name},进程的id为{os.getpid()}") #os.getpid()可用于获取当前进程的pid
    time.sleep(2)   #休眠2s
    print("进程要做的事")


if __name__ == '__main__':
    # 目标函数是do_sth 参数是一个元组,传入进程名称
    #下面两种方法都可以建立进程
    # p = Process(target=do_sth('My Process yellow'))
    p = Process(target=do_sth,args=('my process yellow',))
    #启动进程
    p.start()
    #挂起进程
    p.join()

进程 的实现用重写类方法:

import os
import time
from multiprocessing import  Process


def do_sth(name):
    """
    进程要做的事情
    :param name: str 进程的名称
    """
    print(f"进程的名称{name},进程的id:{os.getpid()}")
    time.sleep(2)
    print("进程要做的事情")

class MyProcess(Process):    #继承Process

    def __init__(self,name,*args,**kwargs):
        # #将进程的属性my_name赋值为name。不赋值为name是因为其父类Process中也有属性叫name,后面再继承父类会覆盖前面的赋值
        self.my_name = name
        #继承父类
        super().__init__(*args,**kwargs)

    def run(self):  #重写run函数
        print(f"当前进程的名称{self.my_name},"
              f"进程的id:{os.getpid()}")
        time.sleep(2)   #休眠2s
        print("进程要做的事")

if __name__ == '__main__':
    #创建一个使用继承类实现进程的方法
    p = MyProcess('my process using class')
    #运行进程
    p.start()
    #挂起进程
    p.join()

进程之间的通信

通过使用multiprocess中的Queue实现进程之间的通信。
获取当前进程名称的方法:

1.如果是写一个函数,直接用Process(target =,args = )则需要调用multiprocessing中的current_process.name
2.如果是重写multiprocessing中的Process方法,则直接调用multiprocessing中的self.name即为当前进程的名称

import multiprocessing
import time
from multiprocessing import Process,Queue
from random import randint

class WriteProcess(Process):
    """ 实现写进程 """
    def __init__(self,q,*args,**kwargs):
        self.q = q  #q是 队列
        super().__init__(*args,**kwargs)

    def run(self):
        """实现进程的业务逻辑"""
        #要写的内容
        ls = ['第一行内容',
               '第二行内容',
               '第三行内容']
        for line in ls:
            print(f"当前在写入:{line}")
            self.q.put(line)

            #如何获取当前进程对象的名称?
            #1.如果是写一个函数,直接用Process(target =,args = )则需要调用multiprocessing中的current_process.name()
            #2.如果是重写multiprocessing中的Process方法,则直接调用multiprocessing中的self.name即为当前进程的名称
            print(f"当前进程的名称{self.name}")

            #每写入一次,休息1-6s
            time.sleep(randint(1,6))


class ReadProcess(Process):
    """ 实现读进程 """
    def __init__(self,q,*args,**kwargs):
        self.q = q
        super().__init__(*args,**kwargs)

    def run(self):
        # 用死循环来实现读进程
        while True:
            content = self.q.get()
            print(f"读取到的内容是{content}")
            # 如何获取当前进程对象的名称?
            # 1.如果是写一个函数,直接用Process(target =,args = )则需要调用multiprocessing中的current_process.name
            # 2.如果是重写multiprocessing中的Process方法,则直接调用multiprocessing中的self.name即为当前进程的名称
            print(f"当前进程的名称{multiprocessing.current_process().name}")

if __name__ == '__main__':
    #创建队列对象
    q = Queue()
    #写进程
    writeprocess = WriteProcess(q)
    #读进程
    readprocess = ReadProcess(q) #读写进程采用同一个队列对象
    writeprocess.start()
    readprocess.start()
    writeprocess.join()
    #如果采用读进程阻塞,而读进程为死循环,则读进程无法结束。所以不应该阻塞读进程,应该直接终止terminate读进程
    # readprocess.join()
    readprocess.terminate() #终止读进程,此时程序可直接结束。

进程中的锁

锁有Lock RLock condition。
Lock只能锁一次,RLock和Lock的唯一不同是RLock可以锁定两次
笔记:

 #以追加a+的方式往文件中写 打开文件的编码方式为utf-8
with open(self.file_name,'a+',encoding='utf-8') as f:   
import random
import time
from multiprocessing import Process, Lock


class WriteProcess(Process):
    """ 往文件中写入内容 """
    def __init__(self,file_name,num,lock,*args,**kwargs):
        self.file_name = file_name
        self.num = num
        #锁对象
        self.lock = lock
        super().__init__(*args,**kwargs) #*args, **kwargs 叫魔法参数

    def run(self):
        # 往文件中写内容
        with self.lock:	#必须是self.lock 锁是类的对象。要用self.
            for i in range(5):
                content = f"当前进程名称是{self.name},进程pid是{self.pid}, 数字是{self.num}"
                with open(self.file_name,'a+',encoding='utf-8') as f:    #以追加a+的方式往文件中写 打开文件的编码方式为utf-8
                    f.write(content+'\n') #写入内容
                    #time.sleep(random.randint(1,5)) #随机休息1-5秒钟

if __name__ == '__main__':
    file_name = 'name.txt' 
    #锁的对象
    lock = Lock()
    for x in range(5):
        p = WriteProcess(file_name,x,lock)
        p.start()

进程池

import multiprocessing
from multiprocessing import pool

def run(file_name,num):
     """往文件中写入数据"""
     with open(file_name,'a+',encoding='utf-8') as f:
        now_process = multiprocessing.current_process()
        content = f"当前进程的名称是{now_process.name}," \
                  f"进程的id是{now_process.pid}," \
                  f"要写入的字符是{num}"
        f.write(content+'\n')
        return 'ok'


if __name__ =='__main__':
    #创建一个容量为2的进程池
    pool = multiprocessing.Pool(2)
    file_name = 'tes_using_pool.txt'
    for i in range(20):
        #apply方法是同步方法
        # result = pool.apply(run,args=(file_name,i)) #等价与run(file_name,i)
       
        #使用异步方法
        result = pool.apply_async(run,args=(file_name,i))
        #使用get方法可以得到写入数据返回的结果。
        print(f"{i}----{result.get()}")

    #关闭池子
    pool.close()
    pool.join()

协程(未看懂)

协程的实现

协程的实现的步骤:

  1. 定义协程函数 async def
  2. 创建事件的循环队列 loop = asyncio.get_event_loop()
  3. 注册任务,把任务加入到事件的循环队列中 task = loop.create_task(coroutine)
  4. 等待协程的执行结束 loop.run_until_complete(task)

asyncio模块
asyncio.get_event_loop() 获取事件循环队列
loop.run_until_complete(task) 注册任务到队列
在事件循环中调度其执行前,写成对象不执行任何操作。
asyncio模块用于事件循环

import asyncio
import time


async def do_sth(x):
    """定义协程函数"""
    print(f"等待中:{x}")
    #等待5s再往后执行
    await asyncio.sleep(x)

#判断是否为协程函数
print(asyncio.iscoroutinefunction(do_sth))

coroutine = do_sth(5)
#事件的循环队列
loop = asyncio.get_event_loop()
#注册任务,把任务加到事件循环队列中
task = loop.create_task(coroutine)
print(task)
#等待协程任务执行结束
loop.run_until_complete(task)
print(task)


True
<Task pending name='Task-1' coro=<do_sth() running at D:\python\多线程和进程\协程的实现.py:5>>
等待中:5
<Task finished name='Task-1' coro=<do_sth() done, defined at D:\python\多线程和进程\协程的实现.py:5> result=None>

协程函数的嵌套调用

要得到一个协程函数的运算结果使用await方法
asyncio 异步IO

import asyncio


async def compute(x,y):
    print(f"Compute {x} + {y}")
    await asyncio.sleep(1.0)
    return x + y

async def print_sum(x,y):
    result = await compute(x,y) #使用await才能拿到另一个协程的运算结果。  
    print(f"{x} + {y} = {result}")

#拿到事件循环
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1,2))
loop.close()

协程通信之队列

import asyncio


#使用队列q实现协程函数之间的通信

#往队列中添加数据
async def add(q,name):

    #使用for循环往队列中添加数据
    for i in range(5):
        content = f"当前协程名称{name},写入队列的内容是{i}"
        # asyncio中的队列添加时返回的时写成对象,因此必须在前面加await
        #q.put(i)
        await asyncio.sleep(2)  # 休息2s
        await q.put(i)  #返回的是协程的对象,因此必须await来获取结果。
        print(f"{content},当前队列中的元素个数为{q.qsize()}")

async def reduce(q,name):
    """
    :param q:
    从队列中删除对象
    """
    for i in range(10):
        content = f"当前协程的名称是{name},要删除的内容是{i}"
        result = await q.get()  #获取协程对象,使用await等待协程完成
        print(f"{content},当前元素剩余为{q.qsize()}")


if __name__ =='__main__':
    #准备一个队列
    q = asyncio.Queue(maxsize=5)
    a1 = add(q,'a1')
    a2 = add(q,'a2')
    r1 = reduce(q,'r1')

    #添加到事件队列
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.gather(a1,a2,r1)) #将多个协程同时添加到事件队列中
    loop.close()

你可能感兴趣的:(Python,python,开发语言)