目录
第1关:求素数的个数
第2关:求合数的个数
第3关:交替打印foobarpython
关于第一第二题思考:
(一)起始数字+结束数字 如何判断?
(二)main函数执行的代码功能
(三)光轮老师提出的素数优化代码:
关于第三题思考:
(一)Await作用
(二)关于锁的机制和作用
第1关:求素数的个数
import math
from multiprocessing import cpu_count
from multiprocessing import Pool
'''使用python多进程 求区间[1,n]里 素数个数'''def isPrime(n):# 判断数字是否为素数# 请在此处添加代码 ## *************begin************#if n<=1:return 0if n==2:return 1if n % 2 ==0: #毛:注意此行必写,否则没有考虑到2这个数,循环从3开始,忽略了2return 0for i in range(3, int(math.sqrt(n)) + 1,2):if n%i == 0:return 0return 1# **************end*************#def howMany(T):# 计算给定区间含有多少个素数# 请在此处添加代码 ## *************begin************#sum = 0for i in range(T[0],T[1]+1):if isPrime(i):sum+=1return sum # **************end*************#def separateNum(N, CPU_COUNT):# 将整个数字空间N分成CPU_COUNT个部分# 请在此处添加代码 ## *************begin************##使用列表推导式生成一个二维列表list#每个子列包含CPU_COUNT个子列表,每个子列表包含2个元素:#起始数字:i*(N//CPU_COUNT)+1#结束数字:(i+1)*(N//CPU_COUNT)list = [[i * (N//CPU_COUNT)+1, (i+1)*(N // CPU_COUNT)] for i in range(0,CPU_COUNT)]list[0][0] =1if list[CPU_COUNT - 1][1] <N:list[CPU_COUNT - 1][1] = Nreturn list # **************end*************#
if __name__ == '__main__':N = int(input()) #输入一个整数N(区间[1,N]中的素数个数)CPU_COUNT = cpu_count() #获取当前计算机CPU内核数 本机为8,存储在CPU_COUNT中pool = Pool(CPU_COUNT) #创建一个进程池,使用CPU_COUNT个进程sepList = separateNum(N, CPU_COUNT) #区间[1,N]分成CPU_COUNT个部分,存储在列表seqList中result = []#创建空列表result,存储异步任务结果for i in range(CPU_COUNT):result.append(pool.apply_async(howMany, (sepList[i], ))) #启动异步进程,计算个数,存储列表中pool.close()#关闭进程池,等待所有进程执行完毕pool.join() #使用列表推导式将result列表中的结果提取出来,存储在列表list中list = [res.get() for res in result]print(sum(list), end = '')#计算素数和,输出
素数优化:设置从3开始,步长为2 ,进行优化
第2关:求合数的个数
import threading
import math
ans = 0
lock = threading.Lock()def isPrime(n):# 判断数字是否为素数global ansif n <= 1:return Falsefor i in range(2, int(math.sqrt(n)) + 1):if n % i == 0:return Falsereturn Truedef howMany(T):# 计算给定区间含有多少个素数sum = 0for i in range(T[0], T[1] + 1):if isPrime(i):sum += 1lock.acquire()try:global ansans += sumfinally:lock.release()def seprateNum(N, CPU_COUNT):# 对整个数字空间N进行分段CPU_COUNTlist = [[i * (N // CPU_COUNT) + 1, (i + 1) * (N // CPU_COUNT)] for i in range(0, CPU_COUNT)]list[0][0] = 1if list[CPU_COUNT - 1][1] < N:list[CPU_COUNT - 1][1] = Nreturn listif __name__ == '__main__': #当前脚本是主程序N = int(input()) #获取用户输入的整数,转化为整型,赋值给变量NthreadNum = 32 #线程数设为32# *************begin************#t = [] #定义一个线程列表tsepList = seprateNum(N,threadNum)#将整数N划分为threadNum个部分for i in range(0,threadNum): #生成线程,存储在列表t中t.append(threading.Thread(target = howMany,args = (sepList[i],))) #将函数howmany作为线程的执行函数,传入sepList[i]中作为参数t[i].start() #启动线程for i in range(0,threadNum): #等所有线程执行结束t[i].join()print(N-1-ans,end='') #计算ans的值,将N-1-ans的值输出,不换行#ans:满足要求的数的个数,剩余数个数# **************end*************#
第3关:交替打印foobarpython
import threading
import sys
import timedef showfoo(n):''':param n: 要输出foobarpython的次数:return: 无返回,可直接输出'''# *************begin************##注意缩进:这个for空4个格子for i in range(n): #循环n次lockpython.acquire() #获取锁,保证线程同步,锁名为:lockpythonprint('foo',end='') #输出'foo',确保不换行sys.stdout.flush() #刷新输出缓存lockfoo.release() #释放锁(保证线程同步),锁名为lockfootime.sleep(0.2) #线程休眠0.2S# **************end*************#def showbar(n):''':param n: 要输出foobarpython的次数:return: 无返回,可直接输出'''
# *************begin************#for i in range(n):lockfoo.acquire()print('bar',end='')sys.stdout.flush()lockbar.release()time.sleep(0.2)
# **************end*************#def showpython(n):''':param n: 要输出foobarpython的次数:return: 无返回,可直接输出'''# 请在此处添加代码 #
# *************begin************#for i in range(n):lockbar.acquire()print('python',end='')sys.stdout.flush()lockpython.release()time.sleep(0.2)
# **************end*************#if __name__ == '__main__':lockfoo = threading.Lock() # 定义3个互斥锁lockbar = threading.Lock()lockpython =threading.Lock()n = int(input())t1 = threading.Thread(target=showfoo,args=[n]) # 定义3个线程t2 = threading.Thread(target=showbar,args=[n])t3 = threading.Thread(target=showpython,args=[n])lockfoo.acquire() # 先锁住foo,bar锁,保证先打印foolockbar.acquire()#lockpython.acquire()t1.start()t2.start()t3.start()
关于第一第二题思考:
(一)起始数字+结束数字 如何判断?
i代表当前正在处理的部分的索引,从0到CPU_COUNT-1。在每个循环中,我们使用i计算当前部分的起始数字和结束数字,具体地:
起始数字:i * (N // CPU_COUNT) + 1,这是因为第一个部分的起始数字应该是1,而每个部分包含的数字个数是N // CPU_COUNT,因此第i个部分的起始数字应该是(i * (N // CPU_COUNT)) + 1。
结束数字:(i + 1) * (N // CPU_COUNT),这是因为第i个部分的结束数字应该比起始数字多包含(N // CPU_COUNT)个数字,而第(i+1)个部分的起始数字应该是第i个部分的结束数字+1,因此第i个部分的结束数字应该是(i+1) * (N // CPU_COUNT) - 1 + 1,即(i+1) * (N // CPU_COUNT)。
举个例子,如果N=100,CPU_COUNT=4,那么我们要将数字1~100分为4个部分,每个部分包含的数字个数是25。
对于第0个部分,其起始数字为0 * 25 + 1 = 1,结束数字为(0+1) * 25 = 25。
对于第1个部分,其起始数字为1 * 25 + 1 = 26,结束数字为(1+1) * 25 = 50。
对于第2个部分,其起始数字为2 * 25 + 1 = 51,结束数字为(2+1) * 25 = 75。
对于第3个部分,其起始数字为3 * 25 + 1 = 76,结束数字为(3+1) * 25 = 100。
因此,二维列表list的每个子列表都包含了一个部分的起始数字和结束数字。
(二)main函数执行的代码功能
首先判断当前文件是否作为主程序运行,如果是则执行下面的代码,如果不是则不执行。
1、输入一个整数N,表示要求区间[1,N]中的素数个数。
2、获取当前计算机的CPU核心数,存储在变量CPU_COUNT中。
3、创建一个进程池对象pool,使用CPU_COUNT个进程。
4、将区间[1,N]分成CPU_COUNT个部分,存储在列表sepList中。
5、创建一个空列表result,用于存储异步任务的结果。
使用pool.apply_async()方法对每个子区间sepList[i]启动一个异步进程,计算该区间内的素数个数,并将结果存储在result列表中。
6、关闭进程池,等待所有进程执行完毕。
使用列表推导式将result列表中的结果提取出来,存储在列表list中。
计算所有子区间内的素数个数之和,将结果输出。
(三)光轮老师提出的素数优化代码:
关于第三题思考:
(一)Await作用
await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值。它只能在异步函数或者模块顶层中使用。
(二)关于锁的机制和作用:
我们需要控制三个线程的执行顺序,保证每个线程在执行一次后,只有另外一个线程才能开始执行。所以我们需要使用锁机制来实现线程同步。
在showfoo函数中,我们需要保证先打印’foo’,因此在函数开始时,先使用lockpython.acquire()来锁住python锁,保证showpython函数不会先执行。然后在打印完’foo’后,使用lockfoo.release()来释放foo锁,让showbar函数可以执行。
在showbar函数中,我们需要保证先打印’bar’,因此在函数开始时,先使用lockfoo.acquire()来锁住foo锁,保证showfoo函数已经执行完毕。然后在打印完’bar’后,使用lockbar.release()来释放bar锁,让showpython函数可以执行。
在showpython函数中,我们需要保证先打印’python’,因此在函数开始时,先使用lockbar.acquire()来锁住bar锁,保证showbar函数已经执行完毕。然后在打印完’python’后,使用lockpython.release()来释放python锁,让showfoo函数可以执行。
这三个锁的作用就是控制三个函数的执行顺序,保证每个函数执行一次后,只有另外一个函数才能执行。