程序,进程,线程(thread)与协程(coroutine)

https://www.cnblogs.com/dhcn/p/9032461.html
代码实现

1. 程序:

  • 静态的代码
  • 运行时至少创建一个进程

2. 进程:

  • 执行起来的代码
  • 程序的执行实例、动态的
  • 进程占用内存资源
  • 一个进程至少包含一个线程,即主线程
  • 同时也可以创建多个子线程
  • 进程之间的内存空间是独立的,数据也是独立的

3. 线程:

  • 程序执行的最小单元
  • 是CPU的可执行上下文
  • 同一个进程中的线程共享同一内存空间,数据共享
  • 线程数据的安全性需要保护
import threading

class MyThread(threading.Thread):
    def __init__(self, thread_name):
        super(MyThread,self).__init__(name)
  1. 方法一
import threading
class MyThread(threading.Thread):
    def __init__(self, thread_name):
        super(MyThread,self).__init__(name = thread_name)

    def run(self):
        print("%s 在执行中"%self.name)

for i in range(10):
    MyThread("testThread"+str(i)).start
  1. 方法二(推荐)
import threading
def show(num):
    print(f"当前线程:{num}在执行…………")

for i in range(10):
    t = threading.Thread(target=show, args=(i,))
    t.start()
#可读性更强,推荐使用
  1. 守护与等待
import threading
import time

def dowaiting():
    print(f'{threading.current_thread().getName()}子线程开始等待...')
    time.sleep(3)
    print(f'{threading.current_thread().getName()}子进程等待结束')

print('主线程开始')
for i in range(3):
    t = threading.Thread(target=dowaiting)
    #守护进程,主程序结束,子程序就会结束
    t.setDaemon(True)
    t.start()
print("主线程的其他操作")

#使得主线程等待全部子线程结束后再执行
t.join()

print("主线程结束")
  1. 线程不安全
    多线程中间的数据共享问题——线程不安全,并发修改number是非常危险的,子线程会记忆自己上一次结束时的结果,导致产生脏数据
import threading
number = 0

def add():
    global number
    for _ in range(1000000):
        number += 1
    print(f"子线程{threading.current_thread().getName()}执行结束后:{number}")

for i in range(2):
    t = threading.Thread(target=add)
    t.start()

time.sleep(3)
print(f"主线程结束,number")

线程安全与线程锁

  • 互斥锁 threading.Lock
  • 可重入锁 threading.RLock
  • 信号 threading.Semaphore
  • 事件 threading.Event
  • 条件 threading.Condition
  • 阻碍 threading.Barrier
    image
#Lock 红绿灯
import threading
number = 0
lock = threading.Lock()

def add(lk):
    global number
    lk.acquire()
    for _ in range(1000000):
        number += 1
    print(f"子线程{threading.current_thread().getName()}执行结束后:{number}")
    lk.release()

for i in range(2):
    t = threading.Thread(target=add, args=(lock,))
    t.start()

def add(lk):
    global number
    with lk:
        for _ in range(1000000):
            number += 1
        print(f"子线程{threading.current_thread().getName()}执行结束后:{number}")

4. 协程

核心参考,写的真的太太太好了[1]

  • 协程是协同运行的例程,相较于线程(thread),允许用户的主动调用和主动退出,挂起当前的例程然后返回值,或去执行其他任务,接着返回原来停下的点继续执行。
    image
import asyncio

async def compute(x, y):
    print("Compute %s + %s ..." % (x, y))
    await asyncio.sleep(1.0)
    return x + y

async def print_sum(x, y):
    result = await compute(x, y)
    print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()

image
当事件循环开始运行时,它会在 Task 中寻找 coroutine 来执行调度,因为事件循环注册了 print_sum(),因此 print_sum() 被调用,执行 result = await compute(x, y) 这条语句(等同于result = yield from compute(x, y)),因为compute()自身就是一个coroutine,因此print_sum()这个协程就会暂时被挂起,compute()被加入到事件循环中,程序流执行compute()中的print语句,打印”Compute %s + %s …”,然后执行了await asyncio.sleep(1.0),因为asyncio.sleep()也是一个coroutine,接着compute()就会被挂起,等待计时器读秒,在这1秒的过程中,事件循环会在队列中查询可以被调度的coroutine,而因为此前print_sum()compute()都被挂起了,因此事件循环会停下来等待协程的调度,当计时器读秒结束后,程序流便会返回到compute()中执行return语句,结果会返回到print_sum()中的result中,最后打印result,事件队列中没有可以调度的任务了,此时loop.close()把事件队列关闭,程序结束。

会JS的同学是不是感觉倍感亲切?没错,事件驱动模型就是异步编程的重中之重。


  1. 核心参考 ↩︎

posted @ 2021-05-28 19:01  小康要好好学习  阅读(161)  评论(0编辑  收藏  举报