程序,进程,线程(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)
- 方法一
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
- 方法二(推荐)
import threading
def show(num):
print(f"当前线程:{num}在执行…………")
for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start()
#可读性更强,推荐使用
- 守护与等待
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("主线程结束")
- 线程不安全
多线程中间的数据共享问题——线程不安全,并发修改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
#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. 协程
- 协程是协同运行的例程,相较于线程(thread),允许用户的主动调用和主动退出,挂起当前的例程然后返回值,或去执行其他任务,接着返回原来停下的点继续执行。
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()
当事件循环开始运行时,它会在 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的同学是不是感觉倍感亲切?没错,事件驱动模型就是异步编程的重中之重。