最近在学python的网络编程,学了socket通信,并利用socket实现了一个具有用户验证功能,可以上传下载文件、可以实现命令行功能,创建和删除文件夹,可以实现的断点续传等功能的FTP服务器。但在这当中,发现一些概念区分起来很难,比如并发和并行,同步和异步,阻塞和非阻塞,但是这些概念却很重要。因此在此把它总结下来。
1. 并发 & 并行
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。简言之,是指系统具有处理多个任务的能力。
并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。简言之,是指系统具有同时处理多个任务的能力。
下面我们来两个例子:
import threading #线程
import time
def music():
print('begin to listen music {}'.format(time.ctime()))
time.sleep(3)
print('stop to listen music {}'.format(time.ctime()))
def game():
print('begin to play game {}'.format(time.ctime()))
time.sleep(5)
print('stop to play game {}'.format(time.ctime()))
if __name__ == '__main__':
music()
game()
print('ending.....')
music的时间为3秒,game的时间为5秒,如果按照我们正常的执行,直接执行函数,那么将按顺序顺序执行,整个过程8秒。
import threading #线程
import time
def music():
print('begin to listen music {}'.format(time.ctime()))
time.sleep(3)
print('stop to listen music {}'.format(time.ctime()))
def game():
print('begin to play game {}'.format(time.ctime()))
time.sleep(5)
print('stop to play game {}'.format(time.ctime()))
if __name__ == '__main__':
t1 = threading.Thread(target=music) #创建一个线程对象t1 子线程
t2 = threading.Thread(target=game) #创建一个线程对象t2 子线程
t1.start()
t2.start()
# t1.join() #等待子线程执行完 t1不执行完,谁也不准往下走
t2.join()
print('ending.......') #主线程
print(time.ctime())
在这个例子中,我们开了两个线程,将music和game两个函数分别通过线程执行,运行结果显示两个线程同时开始,由于听音乐时间3秒,玩游戏时间5秒,所以整个过程完成时间为5秒。我们发现,通过开启多个线程,原本8秒的时间缩短为5秒,原本顺序执行现在是不是看起来好像是并行执行的?看起来好像是这样,听音乐的同时在玩游戏,整个过程的时间随最长的任务时间变化。但真的是这样吗?那么下面我来提出一个GIL锁的概念。
GIL(全局解释器锁):无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行。
import time
from threading import Thread
def add():
sum = 0
i = 1
while i<=1000000:
sum += i
i += 1
print('sum:',sum)
def mul():
sum2 = 1
i = 1
while i<=100000:
sum2 = sum2 * i
i += 1
print('sum2:',sum2)
start = time.time()
add()
mul() #串行比多线程还快
print('cost time %s'%(time.time()-st