首页 > 编程语言 >并发编程

并发编程

时间:2022-10-29 22:12:01浏览次数:34  
标签:__ name img 编程 print 并发 time 进程

并发编程

并发:多个进程在某个时间,一起运行
并行:多个进程在某个时刻,一起运行

python中对并发编程的支持

多线程:threading模块,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴的等待IO完成
多进程:multiprocessing模块,利用多核CPU的能力,真正的并行执行任务
进程池和线程池
异步IO:asyncio模块,在单线程利用CPU和IO同时执行的原理,实现函数异步执行
各自优缺点
多线程:
  优点:相比进程,更加轻量级,占用资源少
  缺点:相比协程,启动数目有限,占用内存资源,有线程切换开销
适用于:IO密集型计算,同时运行的任务数目要求不多
IO密集型:IO密集型指的是系统运作大部分的状况是CPU在等待I/O,
例如一些磁盘、内存、网络的读写,这种状况,CPU占用率不高,系统IO特别高。
典型的示例:文件处理程序,网络爬虫,读写数据库等
多进程
  优点:可以利用多核CPU并行运算
  缺点:占用资源最多,可启动数目比线程少
  适用于:CPU密集型计算场景
  CPU密集型:CPU密集型也叫计算密集型,是指I/O在很短的时间就可以完成,
            CPU需要大量的计算和处理,特点是CPU占用率特别高。
            典型的示例:压缩、解压缩,加密解密,正则表达式搜索等
多协程
  优点:内存开销最少,启动协程数可以非常多
  缺点:支持的库有限,例如不能使用requests模块,代码实现复杂
  适用于:IO密集型计算、需要超多任务运行,有现成库支持的场景

进程

代码实现
from multiprocessing import Process
import os
import time
def run_proc(name):
  print('Run child process name:%s (child id:%s,parent id:%s) ...'
  %(name,os.getpid(),os.getppid())
)
  time.sleep(1)

if __name__ == '__main__':
  print('Parent process %s'%os.getpid())
  argsl = ['z','l', 'y', 'd']
  for i in argsl:
    p = Process(target=run_proc,args=(i,)) # 轮询执行子进程
    print('Child process will start {}'.format(i))
    p.start() # 启动子进程
    p.join()
    # join方法等待子进程结束后继续往下执行,否则启动子进程后不会等待进程结束,
    直接往下执行
  print('Child process end')
进程池
进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,
就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,
而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,
任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。
代码实现
from multiprocessing import Pool
import os

def run(id):
  print("parebt is {} and child id is {}".format(id,os.getpid()))

if __name__ == '__main__':
  pl= Pool(10)
  res=[]
  for i in range(10):
      res.append(pl.apply_async(run,args=(os.getpid(),)))
  g = [i.get for i in res]
  pl.close()
  pl.join()

相关参数理论知识:

1、apply(func[, args[, kwds]]) :
  apply用于传递不定参数,同python中的apply函数一致
  (不过内置的apply函数从2.3以后就不建议使用了),主进程会阻塞于函数。
2、apply_async(func[, args[, kwds[, callback]]]) :
  与apply用法一致,但它是非阻塞的且支持结果返回后进行回调。
  主进程循环运行过程中不等待apply_async的返回结果,
  在主进程结束后,即使子进程还未返回整个程序也会退出。
  虽然 apply_async是非阻塞的,但其返回结果的get方法却是阻塞的,
  如使用result.get()会阻塞主进程。如果我们对返回结果不感兴趣,
  那么可以在主进程中使用pool.close与pool.join来防止主进程退出。
  注意join方法一定要在close或terminate之后调用。
3、map(func, iterable[, chunksize]) :
  map方法与在功能上等价与内置的map(),只不过单个任务会并行运行。
  它会使进程阻塞直到结果返回。
  但需注意的是其第二个参数虽然描述的为iterable,
  但在实际使用中发现只有在整个队列全部就绪后,程序才会运行子进程。
4、map_async(func, iterable[, chunksize[, callback]]) :
  与map用法一致,但是它是非阻塞的。其有关事项见apply_async。
5、imap(func, iterable[, chunksize]) :
  与map不同的是, imap的返回结果为iter,
  需要在主进程中主动使用next来驱动子进程的调用。
  即使子进程没有返回结果,主进程对于gen_list(l)的 iter还是会继续进行,
6、imap_unordered(func, iterable[, chunksize]) :
同imap一致,只不过其并不保证返回结果与迭代传入的顺序一致。
7、close() :
关闭pool,使其不再接受新的任务。
8、terminate() :
结束工作进程,不再处理未处理的任务。
9、join() :
主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。

线程

import threading
import time,os
def single(id):
  time.sleep(1)
  print("single parebt is {} and child id is {}".format(id,os.getpid()))

def dance(id):
  print("dance parebt is {} and child id is {}".format(id,os.getpid()))
if __name__ == '__main__':
  t1 = threading.Thread(target=single,args=(1,))
  t2 = threading.Thread(target=dance,args=(2,))
  t1.start()
  t2.start()

解决多线程无序问题

import threading
import random
from time import sleep

lock = threading.Lock()
list1 = [0] * 10


def task1():
  lock.acquire()
  for i in range(len(list1)):
      print(list1)
      list1[i] = 1
      sleep(0.1)
  lock.release()


def task2():
  lock.acquire()
  for i in range(len(list1)):
      print('---->', list1[i])
      sleep(0.1)
  lock.release()

if __name__ == '__main__':
  t1 = threading.Thread(target=task1)
  t2 = threading.Thread(target=task2)
  t1.start()
  t2.start()

  t1.join()
  t2.join()
线程池
import time
from concurrent.futures import ThreadPoolExecutor

def get_thread_time(times):
  time.sleep(times)
  return times

# 创建线程池 指定最大容纳数量为4
executor = ThreadPoolExecutor(max_workers=4)
# 通过submit提交执行的函数到线程池中
task1 = executor.submit(get_thread_time, (1))
task2 = executor.submit(get_thread_time, (2))
print("task1:{} ".format(task1.done()))#false
print("task2:{}".format(task2.done()))#false
time.sleep(1)
print('after 1s {}'.format('-'*20))

done_map = {
  "task1":task1.done(),#ture
  "task2":task2.done()#false
}
# 2.5秒之后,线程的执行状态
for task_name,done in done_map.items():
  if done:
      print("{}:completed".format(task_name))#

协程

协程称之为函数中断,微线程
import time,asyncio

async def save_img(index, img_url):
  path = "皮肤/" + img_url['name']
  if not os.path.exists(path):
      os.makedirs(path)
  time.sleep(1)
  content = requests.get(img_url['imgLink'], headers=headers).content
  with open('./皮肤/' + img_url['name'] + '/' + img_url['skin_name']
  + str(index) + '.jpg', 'wb') as f:
      f.write(content)

def main():
  loop = asyncio.get_event_loop()# 创建事件循环对象
  img_urls = get_img()
  print(len(img_urls))
  tasks = [save_img(img[0], img[1]) for img in enumerate(img_urls)]
  try:
      loop.run_until_complete(asyncio.wait(tasks))
      # 注册加启动(等待结果返回)
  finally:
      loop.close()

if __name__ == '__main__':
  start = time.time()
  main()
  end = time.time()
  print(end - start)

yield

 

 

异步协程
异步相对同步而言,同步意味着有序,异步意味着无序,正因为异步的无序,使得各个程序间的协 调成为一大难题,
异步编程就是解决这一难题的编程,它是以进程、线程、协程、函数/方法作为执 行任务程序的基本单位,
结合回调、事件循环、信号量等机制,以提高程序整体执行效率和并发能 力的编程方式。

 

 

常见框架gevent的使用

 

 

标签:__,name,img,编程,print,并发,time,进程
From: https://www.cnblogs.com/topass123/p/16840023.html

相关文章