Python开发技术—进程和线程1(第1关:求素数的个数 + 第2关:求合数的个数 + 第3关:交替打印foobarpython)

文章提供了使用Python进行多进程计算素数个数和合数个数的代码示例,以及通过线程同步实现交替打印foo,bar和python的方法。主要涉及了isPrime函数优化、进程池与线程的使用,以及互斥锁在控制打印顺序中的应用。
摘要由CSDN通过智能技术生成

目录

第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 0

    if n==2:
        return 1
    if n % 2 ==0: #毛:注意此行必写,否则没有考虑到2这个数,循环从3开始,忽略了2
        return 0

    for i in range(3, int(math.sqrt(n)) + 1,2):
        if n%i == 0:
            return 0
    return 1
    # **************end*************#

def howMany(T):
    # 计算给定区间含有多少个素数
    #        请在此处添加代码       #
    # *************begin************#
    sum = 0
    for i in range(T[0],T[1]+1):
        if isPrime(i):
            sum+=1
    return 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] =1
    if list[CPU_COUNT - 1][1] <N:
        list[CPU_COUNT - 1][1] = N
    return 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 ans
    if n <= 1:
        return False
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return False
    return True
   
def howMany(T):
    # 计算给定区间含有多少个素数
    sum = 0
    for i in range(T[0], T[1] + 1):
        if isPrime(i):
            sum += 1
    lock.acquire()
    try:
        global ans
        ans += sum
    finally:
        lock.release()
   
def seprateNum(N, CPU_COUNT):
    # 对整个数字空间N进行分段CPU_COUNT
    list = [[i * (N // CPU_COUNT) + 1, (i + 1) * (N // CPU_COUNT)] for i in range(0, CPU_COUNT)]
    list[0][0] = 1
    if list[CPU_COUNT - 1][1] < N:
        list[CPU_COUNT - 1][1] = N
    return list

if __name__ == '__main__': #当前脚本是主程序
    N = int(input()) #获取用户输入的整数,转化为整型,赋值给变量N
    threadNum = 32 #线程数设为32
    # *************begin************#
    t = [] #定义一个线程列表t
    sepList = 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 time

def showfoo(n):
    '''
    :param n: 要输出foobarpython的次数
    :return: 无返回,可直接输出
    '''
    # *************begin************#
    #注意缩进:这个for空4个格子
    for i in range(n): #循环n次
      lockpython.acquire() #获取锁,保证线程同步,锁名为:lockpython
      print('foo',end='') #输出'foo',确保不换行
      sys.stdout.flush() #刷新输出缓存
      lockfoo.release() #释放锁(保证线程同步),锁名为lockfoo
      time.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锁,保证先打印foo
    lockbar.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函数可以执行。

这三个锁的作用就是控制三个函数的执行顺序,保证每个函数执行一次后,只有另外一个函数才能执行。

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值