Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何并行运行函数?_Python_Multithreading_Multiprocessing - Fatal编程技术网

Python 如何并行运行函数?

Python 如何并行运行函数?,python,multithreading,multiprocessing,Python,Multithreading,Multiprocessing,我先研究了一下,没有找到我问题的答案。我试图在Python中并行运行多个函数 我有这样的想法: files.py import common#common是一个处理所有IO内容的util类 dir1='C:\folder1' dir2='C:\folder2' 文件名='test.txt' addFiles=[25,5,15,35,45,25,5,15,35,45] def func1(): c=公共。公共() 对于范围内的i(len(addFiles)): c、 createFiles(add

我先研究了一下,没有找到我问题的答案。我试图在Python中并行运行多个函数

我有这样的想法:

files.py
import common#common是一个处理所有IO内容的util类
dir1='C:\folder1'
dir2='C:\folder2'
文件名='test.txt'
addFiles=[25,5,15,35,45,25,5,15,35,45]
def func1():
c=公共。公共()
对于范围内的i(len(addFiles)):
c、 createFiles(addFiles[i],文件名,dir1)
c、 获取文件(dir1)
时间。睡眠(10)
c、 删除文件(添加文件[i],目录1)
c、 获取文件(dir1)
def func2():
c=公共。公共()
对于范围内的i(len(addFiles)):
c、 createFiles(addFiles[i],文件名,dir2)
c、 getFiles(dir2)
时间。睡眠(10)
c、 移除文件(addFiles[i],dir2)
c、 getFiles(dir2)
我想调用func1和func2,让它们同时运行。这些函数不相互交互,也不在同一对象上交互。现在我必须等待func1完成,然后才能启动func2。我该如何做下面这样的事情:

process.py
从文件导入func1、func2
runBothFunc(func1(),func2())
我希望能够同时创建两个目录,因为每分钟我都要计算创建的文件数。如果目录不在那里,它将使我的计时中断。

您可以使用或

由于,
线程化
不太可能实现真正的并行性。因此,
多处理
通常是更好的选择

下面是一个完整的示例:

from multiprocessing import Process

def func1():
  print 'func1: starting'
  for i in xrange(10000000): pass
  print 'func1: finishing'

def func2():
  print 'func2: starting'
  for i in xrange(10000000): pass
  print 'func2: finishing'

if __name__ == '__main__':
  p1 = Process(target=func1)
  p1.start()
  p2 = Process(target=func2)
  p2.start()
  p1.join()
  p2.join()
启动/加入子进程的机制可以很容易地按照
runBothFunc
的思路封装到函数中:

def runInParallel(*fns):
  proc = []
  for fn in fns:
    p = Process(target=fn)
    p.start()
    proc.append(p)
  for p in proc:
    p.join()

runInParallel(func1, func2)

没有办法保证两个函数将同步执行,这似乎是您想要做的

最好将函数分成几个步骤,然后使用
Process.join
在关键的同步点等待这两个步骤完成,就像@aix的回答中提到的那样


这比时间更好。睡眠(10),因为你不能保证精确的时间。使用显式等待,您的意思是在执行下一步之前必须完成该步骤,而不是假设它将在10毫秒内完成,而根据机器上的其他情况,这是不保证的。

如果您是windows用户并且使用python 3,然后,这篇文章将帮助您用python进行并行编程。当您运行一个常用的多处理库的池编程时,您将得到一个关于程序中主函数的错误。这是因为windows没有fork()功能。下面的帖子给出了上述问题的解决方案

因为我使用的是python 3,所以我对程序做了如下更改:

from types import FunctionType
import marshal

def _applicable(*args, **kwargs):
  name = kwargs['__pw_name']
  code = marshal.loads(kwargs['__pw_code'])
  gbls = globals() #gbls = marshal.loads(kwargs['__pw_gbls'])
  defs = marshal.loads(kwargs['__pw_defs'])
  clsr = marshal.loads(kwargs['__pw_clsr'])
  fdct = marshal.loads(kwargs['__pw_fdct'])
  func = FunctionType(code, gbls, name, defs, clsr)
  func.fdct = fdct
  del kwargs['__pw_name']
  del kwargs['__pw_code']
  del kwargs['__pw_defs']
  del kwargs['__pw_clsr']
  del kwargs['__pw_fdct']
  return func(*args, **kwargs)

def make_applicable(f, *args, **kwargs):
  if not isinstance(f, FunctionType): raise ValueError('argument must be a function')
  kwargs['__pw_name'] = f.__name__  # edited
  kwargs['__pw_code'] = marshal.dumps(f.__code__)   # edited
  kwargs['__pw_defs'] = marshal.dumps(f.__defaults__)  # edited
  kwargs['__pw_clsr'] = marshal.dumps(f.__closure__)  # edited
  kwargs['__pw_fdct'] = marshal.dumps(f.__dict__)   # edited
  return _applicable, args, kwargs

def _mappable(x):
  x,name,code,defs,clsr,fdct = x
  code = marshal.loads(code)
  gbls = globals() #gbls = marshal.loads(gbls)
  defs = marshal.loads(defs)
  clsr = marshal.loads(clsr)
  fdct = marshal.loads(fdct)
  func = FunctionType(code, gbls, name, defs, clsr)
  func.fdct = fdct
  return func(x)

def make_mappable(f, iterable):
  if not isinstance(f, FunctionType): raise ValueError('argument must be a function')
  name = f.__name__    # edited
  code = marshal.dumps(f.__code__)   # edited
  defs = marshal.dumps(f.__defaults__)  # edited
  clsr = marshal.dumps(f.__closure__)  # edited
  fdct = marshal.dumps(f.__dict__)  # edited
  return _mappable, ((i,name,code,defs,clsr,fdct) for i in iterable)
from multiprocessing import Pool
from poolable import make_applicable, make_mappable

def cube(x):
  return x**3

if __name__ == "__main__":
  pool    = Pool(processes=2)
  results = [pool.apply_async(*make_applicable(cube,x)) for x in range(1,7)]
  print([result.get(timeout=10) for result in results])
完成此功能后,上述问题代码也会发生如下变化:

from types import FunctionType
import marshal

def _applicable(*args, **kwargs):
  name = kwargs['__pw_name']
  code = marshal.loads(kwargs['__pw_code'])
  gbls = globals() #gbls = marshal.loads(kwargs['__pw_gbls'])
  defs = marshal.loads(kwargs['__pw_defs'])
  clsr = marshal.loads(kwargs['__pw_clsr'])
  fdct = marshal.loads(kwargs['__pw_fdct'])
  func = FunctionType(code, gbls, name, defs, clsr)
  func.fdct = fdct
  del kwargs['__pw_name']
  del kwargs['__pw_code']
  del kwargs['__pw_defs']
  del kwargs['__pw_clsr']
  del kwargs['__pw_fdct']
  return func(*args, **kwargs)

def make_applicable(f, *args, **kwargs):
  if not isinstance(f, FunctionType): raise ValueError('argument must be a function')
  kwargs['__pw_name'] = f.__name__  # edited
  kwargs['__pw_code'] = marshal.dumps(f.__code__)   # edited
  kwargs['__pw_defs'] = marshal.dumps(f.__defaults__)  # edited
  kwargs['__pw_clsr'] = marshal.dumps(f.__closure__)  # edited
  kwargs['__pw_fdct'] = marshal.dumps(f.__dict__)   # edited
  return _applicable, args, kwargs

def _mappable(x):
  x,name,code,defs,clsr,fdct = x
  code = marshal.loads(code)
  gbls = globals() #gbls = marshal.loads(gbls)
  defs = marshal.loads(defs)
  clsr = marshal.loads(clsr)
  fdct = marshal.loads(fdct)
  func = FunctionType(code, gbls, name, defs, clsr)
  func.fdct = fdct
  return func(x)

def make_mappable(f, iterable):
  if not isinstance(f, FunctionType): raise ValueError('argument must be a function')
  name = f.__name__    # edited
  code = marshal.dumps(f.__code__)   # edited
  defs = marshal.dumps(f.__defaults__)  # edited
  clsr = marshal.dumps(f.__closure__)  # edited
  fdct = marshal.dumps(f.__dict__)  # edited
  return _mappable, ((i,name,code,defs,clsr,fdct) for i in iterable)
from multiprocessing import Pool
from poolable import make_applicable, make_mappable

def cube(x):
  return x**3

if __name__ == "__main__":
  pool    = Pool(processes=2)
  results = [pool.apply_async(*make_applicable(cube,x)) for x in range(1,7)]
  print([result.get(timeout=10) for result in results])
我得到的结果是:

[1, 8, 27, 64, 125, 216]

我认为这篇文章可能对一些windows用户有用。

这可以通过一个允许您轻松并行和分发Python代码的系统优雅地完成

要并行化示例,您需要使用
@ray.remote
装饰器定义函数,然后使用
.remote
调用它们

import ray

ray.init()

dir1 = 'C:\\folder1'
dir2 = 'C:\\folder2'
filename = 'test.txt'
addFiles = [25, 5, 15, 35, 45, 25, 5, 15, 35, 45]

# Define the functions. 
# You need to pass every global variable used by the function as an argument.
# This is needed because each remote function runs in a different process,
# and thus it does not have access to the global variables defined in 
# the current process.
@ray.remote
def func1(filename, addFiles, dir):
    # func1() code here...

@ray.remote
def func2(filename, addFiles, dir):
    # func2() code here...

# Start two tasks in the background and wait for them to finish.
ray.get([func1.remote(filename, addFiles, dir1), func2.remote(filename, addFiles, dir2)]) 
如果将相同的参数传递给两个函数,并且参数很大,则更有效的方法是使用
ray.put()
。这样可以避免将大参数序列化两次,并创建它的两个内存副本:

largeData_id = ray.put(largeData)

ray.get([func1(largeData_id), func2(largeData_id)])
重要信息-如果
func1()
func2()
返回结果,则需要按如下方式重写代码:

ret_id1 = func1.remote(filename, addFiles, dir1)
ret_id2 = func2.remote(filename, addFiles, dir2)
ret1, ret2 = ray.get([ret_id1, ret_id2])

与模块相比,使用Ray有许多优点。特别是,相同的代码将在一台机器以及一组机器上运行。有关Ray的更多优点,请参见。

如果您的函数主要执行I/O工作(并且CPU工作较少),并且您有Python 3.2+,则可以使用:


如果您的函数主要执行CPU工作(以及较少的I/O工作),并且您有Python 2.6+,则可以使用以下模块:


似乎只有一个函数需要调用两个不同的参数。这可以通过使用Python 3.2中的
concurrent.futures
map
组合优雅地完成+

import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

def sleep_secs(seconds):
  time.sleep(seconds)
  print(f'{seconds} has been processed')

secs_list = [2,4, 6, 8, 10, 12]
现在,如果您的操作是IO绑定的,那么您可以使用
ThreadPoolExecutor

with ThreadPoolExecutor() as executor:
  results = executor.map(sleep_secs, secs_list)
注意这里如何使用
map
将函数映射到参数列表

现在,如果函数受CPU限制,则可以使用
ProcessPoolExecutor

with ProcessPoolExecutor() as executor:
  results = executor.map(sleep_secs, secs_list)
如果你不确定,你可以两个都试一下,看看哪一个效果更好

最后,如果您希望打印结果,只需执行以下操作:

with ThreadPoolExecutor() as executor:
  results = executor.map(sleep_secs, secs_list)
  for result in results:
    print(result)

2021年,最简单的方法是使用asyncio:

import asyncio, time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():

    task1 = asyncio.create_task(
        say_after(4, 'hello'))

    task2 = asyncio.create_task(
        say_after(3, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")


asyncio.run(main())
参考文献:


[1]

我使用了你的代码,但函数仍然没有在同一时间启动。@Lamar McAdory:请解释“同时”的确切含义,也许可以给出一个具体的例子,说明你做了什么,你期望发生什么,以及实际发生了什么。@Lamar:你永远不能保证“完全同时”认为你能做到是完全错误的。根据您拥有的CPU数量、机器负载、计算机上发生的许多事情的时间,这些都会影响线程/进程的启动时间。此外,由于进程是在创建之后立即启动的,因此创建进程的开销也必须根据您看到的时间差进行计算。是否可以获得每个函数的结果列表?假设每个函数返回一个不同的值,这些值是否可以附加到某个列表中供以后使用?可能会将结果附加到全局列表中?如果我的函数采用参数,当我