concurrent.futures --- Khởi chạy các tác vụ song song

Added in version 3.2.

Source code: Lib/concurrent/futures/thread.py, Lib/concurrent/futures/process.py, và Lib/concurrent/futures/interpreter.py


Mô-đun concurrent.futures cung cấp giao diện cấp cao để thực thi lệnh gọi không đồng bộ.

Việc thực thi không đồng bộ có thể được thực hiện bằng các luồng, sử dụng ThreadPoolExecutor hoặc InterpreterPoolExecutor hoặc các quy trình riêng biệt, sử dụng ProcessPoolExecutor. Mỗi cái thực hiện cùng một giao diện, được xác định bởi lớp Executor trừu tượng.

Không được nhầm lẫn concurrent.futures.Future với asyncio.Future, được thiết kế để sử dụng với các tác vụ và coroutine asyncio. Xem tài liệu asyncio's Future để có sự so sánh chi tiết về cả hai.

sẵn có: not WASI.

Mô-đun này không hoạt động hoặc không có trên WebAssembly. Xem Nền tảng WebAssugging để biết thêm thông tin.

Đối tượng thực thi

class concurrent.futures.Executor

Một lớp trừu tượng cung cấp các phương thức để thực hiện các cuộc gọi không đồng bộ. Nó không nên được sử dụng trực tiếp mà thông qua các lớp con cụ thể của nó.

submit(fn, /, *args, **kwargs)

Lập lịch cho đối tượng có thể gọi được, fn, được thực thi dưới dạng fn(*args, **kwargs) và trả về một đối tượng Future thể hiện việc thực thi đối tượng có thể gọi được.

với ThreadPoolExecutor(max_workers=1)  người thực thi:
    tương lai = executor.submit(pow, 323, 1235)
    in(tương lai.result())
map(fn, *iterables, timeout=None, chunksize=1, buffersize=None)

Tương tự như map(fn, *iterables) ngoại trừ:

  • iterables được thu thập ngay lập tức thay vì một cách lười biếng, trừ khi buffersize được chỉ định để giới hạn số lượng nhiệm vụ được gửi mà chưa mang lại kết quả. Nếu bộ đệm đầy, quá trình lặp qua iterables sẽ tạm dừng cho đến khi có kết quả từ bộ đệm.

  • fn được thực thi không đồng bộ và một số lệnh gọi đến fn có thể được thực hiện đồng thời.

Trình vòng lặp được trả về sẽ tăng TimeoutError nếu __next__() được gọi và kết quả không có sau timeout giây kể từ lệnh gọi ban đầu tới Executor.map(). timeout có thể là int hoặc float. Nếu timeout không được chỉ định hoặc None, sẽ không có giới hạn về thời gian chờ.

Nếu lệnh gọi fn đưa ra một ngoại lệ thì ngoại lệ đó sẽ được đưa ra khi giá trị của nó được lấy từ trình vòng lặp.

Khi sử dụng ProcessPoolExecutor, phương pháp này sẽ chia iterables thành một số phần mà nó gửi tới nhóm dưới dạng các tác vụ riêng biệt. Kích thước (gần đúng) của các khối này có thể được chỉ định bằng cách đặt chunksize thành số nguyên dương. Đối với các lần lặp rất dài, việc sử dụng giá trị lớn cho chunksize có thể cải thiện đáng kể hiệu suất so với kích thước mặc định là 1. Với ThreadPoolExecutorInterpreterPoolExecutor, chunksize không có tác dụng.

Thay đổi trong phiên bản 3.5: Đã thêm tham số chunksize.

Thay đổi trong phiên bản 3.14: Đã thêm tham số buffersize.

shutdown(wait=True, *, cancel_futures=False)

Báo hiệu cho người thực thi rằng nó sẽ giải phóng mọi tài nguyên mà nó đang sử dụng khi thực thi xong các hợp đồng tương lai hiện đang chờ xử lý. Các lệnh gọi tới Executor.submit()Executor.map() được thực hiện sau khi tắt máy sẽ tăng RuntimeError.

Nếu waitTrue thì phương thức này sẽ không trả về cho đến khi tất cả các tương lai đang chờ xử lý được thực thi xong và các tài nguyên liên quan đến người thực thi đã được giải phóng. Nếu waitFalse thì phương thức này sẽ trả về ngay lập tức và các tài nguyên được liên kết với người thực thi sẽ được giải phóng khi tất cả các tương lai đang chờ xử lý được thực thi xong. Bất kể giá trị của wait là bao nhiêu, toàn bộ chương trình Python sẽ không thoát cho đến khi tất cả các hợp đồng tương lai đang chờ xử lý được thực thi xong.

Nếu cancel_futuresTrue, phương thức này sẽ hủy tất cả các hợp đồng tương lai đang chờ xử lý mà người thi hành chưa bắt đầu chạy. Mọi hợp đồng tương lai đã hoàn thành hoặc đang chạy sẽ không bị hủy, bất kể giá trị của cancel_futures.

Nếu cả cancel_futureswait đều là True thì tất cả các hợp đồng tương lai mà người thi hành đã bắt đầu chạy sẽ được hoàn thành trước khi phương thức này quay trở lại. Các hợp đồng tương lai còn lại bị hủy bỏ.

Bạn có thể tránh phải gọi phương thức này một cách rõ ràng nếu bạn sử dụng trình thực thi làm context manager thông qua câu lệnh with, câu lệnh này sẽ tắt Executor (chờ như thể Executor.shutdown() được gọi với wait được đặt thành True):

nhập khẩu
với ThreadPoolExecutor(max_workers=4)  e:
    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
    e.submit(shutil.copy, 'src4.txt', 'dest4.txt')

Thay đổi trong phiên bản 3.9: Đã thêm cancel_futures.

ThreadPoolExecutor

ThreadPoolExecutor là một lớp con Executor sử dụng một nhóm luồng để thực hiện các cuộc gọi không đồng bộ.

Bế tắc có thể xảy ra khi lệnh gọi được liên kết với Future chờ kết quả của Future khác. Ví dụ:

thời gian nhập khẩu
chắc chắn wait_on_b():
    thời gian.ngủ(5)
    print(b.result()) # b sẽ không bao giờ hoàn thành vì nó đang chờ a.
    trở lại 5

chắc chắn wait_on_a():
    thời gian.ngủ(5)
    print(a.result()) # a sẽ không bao giờ hoàn thành vì nó đang chờ b.
    trở lại 6


người thực thi = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b)
b = executor.submit(wait_on_a)

Và:

chắc chắn wait_on_future():
    f = executor.submit(pow, 5, 2)
    # This sẽ không bao giờ hoàn thành vì chỉ có một luồng công nhân và
    # it đang thực thi chức năng này.
    in(f.result())

người thi hành = ThreadPoolExecutor(max_workers=1)
tương lai = executor.submit(wait_on_future)
# Note: gọi Future.result() cũng sẽ gây ra bế tắc vì
Chuỗi công việc đơn # the đang chờ wait_on_future().
class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())

Một lớp con Executor sử dụng một nhóm tối đa các luồng max_workers để thực hiện các cuộc gọi không đồng bộ.

Tất cả các chủ đề được xếp hàng vào ThreadPoolExecutor sẽ được nối trước khi trình thông dịch có thể thoát. Lưu ý rằng trình xử lý thoát thực hiện việc này được thực thi before bất kỳ trình xử lý thoát nào được thêm bằng atexit. Điều này có nghĩa là các ngoại lệ trong luồng chính phải được phát hiện và xử lý để báo hiệu các luồng thoát ra một cách duyên dáng. Vì lý do này, không nên sử dụng ThreadPoolExecutor cho các tác vụ chạy trong thời gian dài.

initializer là một lệnh gọi tùy chọn được gọi ở đầu mỗi chuỗi công việc; initargs là một bộ đối số được truyền cho bộ khởi tạo. Nếu initializer đưa ra một ngoại lệ, tất cả các công việc hiện đang chờ xử lý sẽ đưa ra BrokenThreadPool, cũng như mọi nỗ lực gửi thêm công việc vào nhóm.

Thay đổi trong phiên bản 3.5: Nếu max_workersNone hoặc không được cung cấp, nó sẽ mặc định là số lượng bộ xử lý trên máy, nhân với 5, giả sử rằng ThreadPoolExecutor thường được sử dụng để chồng chéo I/O thay vì công việc CPU và số lượng công nhân phải cao hơn số lượng công nhân cho ProcessPoolExecutor.

Thay đổi trong phiên bản 3.6: Đã thêm tham số thread_name_prefix để cho phép người dùng kiểm soát tên threading.Thread cho các chuỗi công việc do nhóm tạo để gỡ lỗi dễ dàng hơn.

Thay đổi trong phiên bản 3.7: Đã thêm đối số initializerinitargs.

Thay đổi trong phiên bản 3.8: Giá trị mặc định của max_workers được đổi thành min(32, os.cpu_count() + 4). Giá trị mặc định này duy trì ít nhất 5 công nhân cho các tác vụ liên kết I/O. Nó sử dụng tối đa 32 lõi CPU cho các tác vụ ràng buộc CPU giải phóng GIL. Và nó tránh sử dụng ngầm các tài nguyên rất lớn trên các máy nhiều lõi.

ThreadPoolExecutor hiện sử dụng lại các luồng công việc nhàn rỗi trước khi bắt đầu các luồng công việc max_workers.

Thay đổi trong phiên bản 3.13: Giá trị mặc định của max_workers được đổi thành min(32, (os.process_cpu_count() or 1) + 4).

Ví dụ về ThreadPoolExecutor

nhập đồng thời.futures
nhập urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://nonexistent-subdomain.python.org/']

# Retrieve một trang duy nhất và báo cáo URL và nội dung
def Load_url(url, timeout):
    với urllib.request.urlopen(url, timeout=timeout)  kết nối:
        trả về conn.read()

# We có thể sử dụng câu lệnh with để đảm bảo các luồng được dọn sạch kịp thời
với concurrent.futures.ThreadPoolExecutor(max_workers=5)  người thực thi:
    # Start tải các hoạt động và đánh dấu từng tương lai với URL của nó
    Future_to_url = {executor.submit(load_url, url, 60): url cho url trong URLS}
    cho tương lai trong concurrent.futures.as_completed(future_to_url):
        url = tương lai_to_url[tương lai]
        thử:
            dữ liệu = tương lai.result()
        ngoại trừ Ngoại lệ như exec:
            print('%r đã tạo ra một ngoại lệ: %s' % (url, ex))
        khác:
            print('%r trang is %d bytes' % (url, len(data)))

Thông Dịch ViênPoolNgười Thi Hành

Added in version 3.14.

Lớp InterpreterPoolExecutor sử dụng một nhóm trình thông dịch để thực hiện các cuộc gọi không đồng bộ. Nó là lớp con ThreadPoolExecutor, có nghĩa là mỗi công nhân đang chạy trong luồng riêng của mình. Sự khác biệt ở đây là mỗi nhân viên có trình thông dịch riêng và chạy từng tác vụ bằng trình thông dịch đó.

Lợi ích lớn nhất của việc sử dụng trình thông dịch thay vì chỉ các luồng là tính song song đa lõi thực sự. Mỗi trình thông dịch có Global Interpreter Lock riêng, vì vậy mã chạy trong một trình thông dịch có thể chạy trên một lõi CPU, trong khi mã trong một trình thông dịch khác chạy không bị chặn trên một lõi khác.

Sự cân bằng là việc viết mã đồng thời để sử dụng với nhiều trình thông dịch có thể tốn nhiều công sức hơn. Tuy nhiên, điều này là do nó buộc bạn phải thận trọng về cách thức và thời điểm các thông dịch viên tương tác cũng như phải rõ ràng về dữ liệu nào được chia sẻ giữa các thông dịch viên. Điều này mang lại một số lợi ích giúp cân bằng nỗ lực bổ sung, bao gồm cả tính song song đa lõi thực sự. Ví dụ: mã được viết theo cách này có thể giúp bạn dễ dàng suy luận về tính đồng thời hơn. Một lợi ích lớn khác là bạn không phải đối mặt với một số vấn đề lớn khi sử dụng chuỗi, chẳng hạn như điều kiện chạy đua.

Mỗi thông dịch viên của công nhân được tách biệt khỏi tất cả các thông dịch viên khác. "Bị cô lập" có nghĩa là mỗi trình thông dịch có trạng thái thời gian chạy riêng và hoạt động hoàn toàn độc lập. Ví dụ: nếu bạn chuyển hướng sys.stdout trong một trình thông dịch, nó sẽ không tự động được chuyển hướng đến bất kỳ trình thông dịch nào khác. Nếu bạn nhập một mô-đun vào một trình thông dịch, nó sẽ không được tự động nhập vào bất kỳ trình thông dịch nào khác. Bạn sẽ cần nhập mô-đun riêng biệt vào trình thông dịch nơi bạn cần. Trên thực tế, mỗi mô-đun được nhập vào trình thông dịch là một đối tượng hoàn toàn riêng biệt với cùng một mô-đun trong một trình thông dịch khác, bao gồm sys, builtins và thậm chí __main__.

Cách ly có nghĩa là một đối tượng có thể thay đổi hoặc dữ liệu khác không thể được sử dụng bởi nhiều hơn một trình thông dịch cùng một lúc. Điều đó có nghĩa là người phiên dịch thực sự không thể chia sẻ các đối tượng hoặc dữ liệu đó. Thay vào đó, mỗi trình thông dịch phải có bản sao riêng và bạn sẽ phải đồng bộ hóa mọi thay đổi giữa các bản sao theo cách thủ công. Các đối tượng và dữ liệu bất biến, như các đơn vị, chuỗi và bộ dữ liệu dựng sẵn của các đối tượng bất biến, không có những hạn chế này.

Việc giao tiếp và đồng bộ hóa giữa các trình thông dịch được thực hiện hiệu quả nhất bằng cách sử dụng các công cụ chuyên dụng, giống như những công cụ được đề xuất trong PEP 734. Một giải pháp thay thế kém hiệu quả hơn là tuần tự hóa bằng pickle và sau đó gửi byte qua socket hoặc pipe được chia sẻ.

class concurrent.futures.InterpreterPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())

Một lớp con ThreadPoolExecutor thực hiện các cuộc gọi không đồng bộ bằng cách sử dụng tối đa một nhóm các luồng max_workers. Mỗi luồng chạy các tác vụ trong trình thông dịch riêng của nó. Các trình thông dịch công nhân được tách biệt với nhau, nghĩa là mỗi trình thông dịch có trạng thái thời gian chạy riêng và chúng không thể chia sẻ bất kỳ đối tượng có thể thay đổi hoặc dữ liệu nào khác. Mỗi trình thông dịch có Global Interpreter Lock riêng, có nghĩa là mã chạy với trình thực thi này có tính song song đa lõi thực sự.

Các đối số initializerinitargs tùy chọn có cùng ý nghĩa như đối với ThreadPoolExecutor: trình khởi tạo được chạy khi mỗi công nhân được tạo, mặc dù trong trường hợp này nó được chạy trong trình thông dịch của công nhân. Người thi hành tuần tự hóa initializerinitargs bằng cách sử dụng pickle khi gửi chúng tới trình thông dịch của công nhân.

Ghi chú

Người thi hành có thể thay thế các ngoại lệ chưa được phát hiện từ initializer bằng ExecutionFailed.

Những cảnh báo khác từ ThreadPoolExecutor gốc được áp dụng tại đây.

submit()map() hoạt động như bình thường, ngoại trừ trình chạy tuần tự hóa lệnh gọi và đối số bằng cách sử dụng pickle khi gửi chúng tới trình thông dịch của nó. Tương tự, nhân viên sẽ tuần tự hóa giá trị trả về khi gửi lại.

Khi tác vụ hiện tại của một nhân viên đưa ra một ngoại lệ chưa được nắm bắt, nhân viên đó luôn cố gắng duy trì ngoại lệ đó. Nếu thành công thì nó cũng đặt __cause__ thành một phiên bản ExecutionFailed tương ứng, chứa bản tóm tắt về ngoại lệ ban đầu. Trong trường hợp hiếm gặp là nhân viên không thể giữ nguyên bản gốc thì thay vào đó, nó sẽ trực tiếp bảo toàn phiên bản ExecutionFailed tương ứng.

Người thi hành ProcessPool

Lớp ProcessPoolExecutor là lớp con Executor sử dụng một nhóm quy trình để thực hiện các cuộc gọi không đồng bộ. ProcessPoolExecutor sử dụng mô-đun multiprocessing, cho phép nó vượt qua Global Interpreter Lock nhưng cũng có nghĩa là chỉ những đối tượng có thể chọn mới có thể được thực thi và trả về.

Mô-đun __main__ phải có thể được nhập bởi các quy trình con của nhân viên. Điều này có nghĩa là ProcessPoolExecutor sẽ không hoạt động trong trình thông dịch tương tác.

Việc gọi các phương thức Executor hoặc Future từ một đối tượng có thể gọi được gửi tới ProcessPoolExecutor sẽ dẫn đến bế tắc.

Lưu ý rằng các hạn chế về hàm và đối số cần có thể chọn theo multiprocessing.Process sẽ được áp dụng khi sử dụng submit()map() trên ProcessPoolExecutor. Một hàm được xác định trong REPL hoặc lambda sẽ không hoạt động.

class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)

Một lớp con Executor thực hiện các cuộc gọi không đồng bộ bằng cách sử dụng một nhóm gồm nhiều nhất các quy trình max_workers. Nếu max_workersNone hoặc không được cung cấp, nó sẽ mặc định là os.process_cpu_count(). Nếu max_workers nhỏ hơn hoặc bằng 0 thì ValueError sẽ được nâng lên. Trên Windows, max_workers phải nhỏ hơn hoặc bằng 61. Nếu không thì ValueError sẽ được nâng lên. Nếu max_workersNone thì mặc định được chọn tối đa sẽ là 61, ngay cả khi có nhiều bộ xử lý hơn. mp_context có thể là ngữ cảnh multiprocessing hoặc None. Nó sẽ được sử dụng để khởi động các công nhân. Nếu mp_contextNone hoặc không được cung cấp thì ngữ cảnh multiprocessing mặc định sẽ được sử dụng. Xem Bối cảnh và phương pháp bắt đầu.

initializer là một lệnh gọi tùy chọn được gọi khi bắt đầu mỗi quy trình công nhân; initargs là một bộ đối số được truyền cho bộ khởi tạo. Nếu initializer đưa ra một ngoại lệ, tất cả các công việc hiện đang chờ xử lý sẽ đưa ra BrokenProcessPool, cũng như mọi nỗ lực gửi thêm công việc vào nhóm.

max_tasks_per_child là một đối số tùy chọn chỉ định số lượng tác vụ tối đa mà một quy trình có thể thực thi trước khi nó thoát ra và được thay thế bằng một quy trình công nhân mới. Theo mặc định, max_tasks_per_childNone, có nghĩa là các quy trình công nhân sẽ tồn tại lâu như nhóm. Khi mức tối đa được chỉ định, phương thức bắt đầu đa xử lý "sinh sản" sẽ được sử dụng theo mặc định khi không có tham số mp_context. Tính năng này không tương thích với phương pháp khởi động "ngã ba".

Ghi chú

Các lỗi đã được báo cáo khi sử dụng tính năng max_tasks_per_child có thể khiến ProcessPoolExecutor bị treo trong một số trường hợp. Thực hiện theo độ phân giải cuối cùng của nó trong gh-115634.

Thay đổi trong phiên bản 3.3: Khi một trong các quy trình công nhân chấm dứt đột ngột, lỗi BrokenProcessPool hiện đã xuất hiện. Trước đây, hành vi không được xác định nhưng các hoạt động trên người thực thi hoặc tương lai của nó thường bị đóng băng hoặc bế tắc.

Thay đổi trong phiên bản 3.7: Đối số mp_context đã được thêm vào để cho phép người dùng kiểm soát phương thức start_method cho các quy trình công nhân do nhóm tạo.

Đã thêm đối số initializerinitargs.

Thay đổi trong phiên bản 3.11: Đối số max_tasks_per_child đã được thêm vào để cho phép người dùng kiểm soát thời gian hoạt động của các công nhân trong nhóm.

Thay đổi trong phiên bản 3.12: Trên hệ thống POSIX, nếu ứng dụng của bạn có nhiều luồng và ngữ cảnh multiprocessing sử dụng phương thức khởi động "fork": Hàm os.fork() được gọi nội bộ để sinh ra các nhân viên có thể tạo ra một DeprecationWarning. Chuyển mp_context được định cấu hình để sử dụng phương thức khởi động khác. Xem tài liệu os.fork() để được giải thích thêm.

Thay đổi trong phiên bản 3.13: max_workers sử dụng os.process_cpu_count() theo mặc định, thay vì os.cpu_count().

Thay đổi trong phiên bản 3.14: Phương thức bắt đầu quy trình mặc định (xem Bối cảnh và phương pháp bắt đầu) đã thay đổi so với fork. Nếu bạn yêu cầu phương thức khởi động fork cho ProcessPoolExecutor, bạn phải chuyển mp_context=multiprocessing.get_context("fork") một cách rõ ràng.

terminate_workers()

Cố gắng chấm dứt tất cả các quy trình Worker đang hoạt động ngay lập tức bằng cách gọi Process.terminate trên mỗi quy trình đó. Trong nội bộ, nó cũng sẽ gọi Executor.shutdown() để đảm bảo rằng tất cả các tài nguyên khác liên quan đến người thực thi đều được giải phóng.

Sau khi gọi phương thức này, người gọi sẽ không gửi nhiệm vụ cho người thực thi nữa.

Added in version 3.14.

kill_workers()

Cố gắng loại bỏ tất cả các quy trình công nhân đang hoạt động ngay lập tức bằng cách gọi Process.kill trên mỗi quy trình đó. Trong nội bộ, nó cũng sẽ gọi Executor.shutdown() để đảm bảo rằng tất cả các tài nguyên khác liên quan đến người thực thi đều được giải phóng.

Sau khi gọi phương thức này, người gọi sẽ không gửi nhiệm vụ cho người thực thi nữa.

Added in version 3.14.

Ví dụ về ProcessPoolExecutor

nhập đồng thời.futures
nhập toán

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    nếu n < 2:
        trả về Sai
    nếu n == 2:
        trả về Đúng
    nếu n% 2 == 0:
        trả về Sai

    sqrt_n = int(math.floor(math.sqrt(n)))
    cho tôi trong phạm vi (3, sqrt_n + 1, 2):
        nếu n % i == 0:
            trả về Sai
    trả về Đúng

chắc chắn chính():
    với concurrent.futures.ProcessPoolExecutor() làm người thực thi:
        đối với số, số nguyên tố  dạng zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d là số nguyên tố: %s' % (số, số nguyên tố))

nếu __name__ == '__main__':
    chính()

Đối tượng tương lai

Lớp Future gói gọn việc thực thi không đồng bộ của lệnh gọi. Các phiên bản Future được tạo bởi Executor.submit().

class concurrent.futures.Future

Đóng gói việc thực thi không đồng bộ của một lệnh gọi. Các phiên bản Future được tạo bởi Executor.submit() và không được tạo trực tiếp ngoại trừ để thử nghiệm.

cancel()

Cố gắng hủy cuộc gọi. Nếu cuộc gọi hiện đang được thực hiện hoặc chạy xong và không thể hủy thì phương thức sẽ trả về False, nếu không cuộc gọi sẽ bị hủy và phương thức sẽ trả về True.

cancelled()

Trả về True nếu cuộc gọi được hủy thành công.

running()

Trả về True nếu cuộc gọi hiện đang được thực hiện và không thể hủy được.

done()

Trả về True nếu cuộc gọi bị hủy thành công hoặc chạy xong.

result(timeout=None)

Trả về giá trị được cuộc gọi trả về. Nếu cuộc gọi chưa hoàn thành thì phương thức này sẽ đợi tới timeout giây. Nếu cuộc gọi chưa hoàn thành sau timeout giây thì TimeoutError sẽ được đưa ra. timeout có thể là int hoặc float. Nếu timeout không được chỉ định hoặc None thì không có giới hạn về thời gian chờ.

Nếu tương lai bị hủy trước khi hoàn thành thì CancelledError sẽ được nâng lên.

Nếu cuộc gọi đưa ra một ngoại lệ, phương thức này sẽ đưa ra ngoại lệ tương tự.

exception(timeout=None)

Trả lại ngoại lệ được đưa ra bởi cuộc gọi. Nếu cuộc gọi chưa hoàn thành thì phương thức này sẽ đợi tới timeout giây. Nếu cuộc gọi chưa hoàn thành sau timeout giây thì TimeoutError sẽ được đưa ra. timeout có thể là int hoặc float. Nếu timeout không được chỉ định hoặc None thì không có giới hạn về thời gian chờ.

Nếu tương lai bị hủy trước khi hoàn thành thì CancelledError sẽ được nâng lên.

Nếu cuộc gọi hoàn tất mà không tăng, None sẽ được trả về.

add_done_callback(fn)

Gắn fn có thể gọi được vào tương lai. fn sẽ được gọi, với tương lai là đối số duy nhất của nó, khi tương lai bị hủy hoặc chạy xong.

Các lệnh gọi đã thêm được gọi theo thứ tự chúng được thêm vào và luôn được gọi trong một luồng thuộc quy trình đã thêm chúng. Nếu lệnh gọi được tạo ra một lớp con Exception, nó sẽ được ghi lại và bỏ qua. Nếu lệnh gọi có thể tạo ra một lớp con BaseException thì hành vi đó sẽ không được xác định.

Nếu tương lai đã hoàn thành hoặc bị hủy, fn sẽ được gọi ngay lập tức.

Các phương pháp Future sau đây được sử dụng trong các thử nghiệm đơn vị và triển khai Executor.

set_running_or_notify_cancel()

Phương pháp này chỉ nên được gọi khi triển khai Executor trước khi thực hiện công việc liên quan đến Future và bằng các thử nghiệm đơn vị.

Nếu phương thức trả về False thì Future đã bị hủy, tức là Future.cancel() được gọi và trả về True. Bất kỳ chủ đề nào đang chờ Future hoàn thành (tức là thông qua as_completed() hoặc wait()) sẽ được đánh thức.

Nếu phương thức trả về True thì Future không bị hủy và được đặt ở trạng thái đang chạy, tức là các lệnh gọi tới Future.running() sẽ trả về True.

Phương thức này chỉ có thể được gọi một lần và không thể được gọi sau khi Future.set_result() hoặc Future.set_exception() được gọi.

set_result(result)

Đặt kết quả của công việc liên quan đến Future thành result.

Phương pháp này chỉ nên được sử dụng khi triển khai Executor và kiểm tra đơn vị.

Thay đổi trong phiên bản 3.8: Phương pháp này tăng concurrent.futures.InvalidStateError nếu Future đã được thực hiện.

set_exception(exception)

Đặt kết quả của công việc liên quan đến Future thành Exception exception.

Phương pháp này chỉ nên được sử dụng khi triển khai Executor và kiểm tra đơn vị.

Thay đổi trong phiên bản 3.8: Phương pháp này tăng concurrent.futures.InvalidStateError nếu Future đã được thực hiện.

Chức năng mô-đun

concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)

Đợi các phiên bản Future (có thể được tạo bởi các phiên bản Executor khác nhau) do fs cung cấp hoàn tất. Hợp đồng tương lai trùng lặp được cung cấp cho fs sẽ bị xóa và sẽ chỉ được trả lại một lần. Trả về 2 bộ được đặt tên. Tập đầu tiên, có tên là done, chứa các hợp đồng tương lai đã hoàn thành (các hợp đồng tương lai đã hoàn thành hoặc bị hủy) trước khi quá trình chờ đợi hoàn tất. Bộ thứ hai, có tên là not_done, chứa các hợp đồng tương lai chưa hoàn thành (các hợp đồng tương lai đang chờ xử lý hoặc đang chạy).

timeout có thể được sử dụng để kiểm soát số giây tối đa phải chờ trước khi quay lại. timeout có thể là int hoặc float. Nếu timeout không được chỉ định hoặc None thì không có giới hạn về thời gian chờ.

return_when cho biết khi nào hàm này sẽ quay trở lại. Nó phải là một trong các hằng số sau:

Hằng số

Mô tả

concurrent.futures.FIRST_COMPLETED

Hàm sẽ quay trở lại khi bất kỳ thao tác nào trong tương lai kết thúc hoặc bị hủy.

concurrent.futures.FIRST_EXCEPTION

Hàm sẽ trả về khi bất kỳ tương lai nào kết thúc bằng cách đưa ra một ngoại lệ. Nếu không có tương lai nào đưa ra ngoại lệ thì nó tương đương với ALL_COMPLETED.

concurrent.futures.ALL_COMPLETED

Hàm sẽ trả về khi tất cả hợp đồng tương lai kết thúc hoặc bị hủy.

concurrent.futures.as_completed(fs, timeout=None)

Trả về một trình vòng lặp trên các phiên bản Future (có thể được tạo bởi các phiên bản Executor khác nhau) do fs cung cấp, mang lại tương lai khi chúng hoàn thành (tương lai đã hoàn thành hoặc bị hủy). Bất kỳ hợp đồng tương lai nào do fs cung cấp bị trùng lặp sẽ được trả lại một lần. Bất kỳ hợp đồng tương lai nào hoàn thành trước khi as_completed() được gọi sẽ được trả trước. Trình lặp được trả về sẽ tăng TimeoutError nếu __next__() được gọi và kết quả không có sau timeout giây kể từ lệnh gọi ban đầu tới as_completed(). timeout có thể là int hoặc float. Nếu timeout không được chỉ định hoặc None thì không có giới hạn về thời gian chờ.

Xem thêm

PEP 3148 -- tương lai - thực hiện tính toán không đồng bộ

Đề xuất mô tả tính năng này để đưa vào thư viện chuẩn Python.

Các lớp ngoại lệ

exception concurrent.futures.CancelledError

Tăng lên khi một tương lai bị hủy bỏ.

exception concurrent.futures.TimeoutError

Bí danh TimeoutError không được dùng nữa, được nêu ra khi một thao tác trong tương lai vượt quá thời gian chờ nhất định.

Thay đổi trong phiên bản 3.11: Lớp này được đặt bí danh là TimeoutError.

exception concurrent.futures.BrokenExecutor

Bắt nguồn từ RuntimeError, lớp ngoại lệ này được nâng lên khi bộ thực thi bị hỏng vì lý do nào đó và không thể được sử dụng để gửi hoặc thực thi các tác vụ mới.

Added in version 3.7.

exception concurrent.futures.InvalidStateError

Xảy ra khi một thao tác được thực hiện trong tương lai không được phép ở trạng thái hiện tại.

Added in version 3.8.

exception concurrent.futures.thread.BrokenThreadPool

Bắt nguồn từ BrokenExecutor, lớp ngoại lệ này được đưa ra khi một trong các công nhân của ThreadPoolExecutor khởi tạo không thành công.

Added in version 3.7.

exception concurrent.futures.interpreter.BrokenInterpreterPool

Bắt nguồn từ BrokenThreadPool, lớp ngoại lệ này được đưa ra khi một trong các công nhân của InterpreterPoolExecutor khởi tạo không thành công.

Added in version 3.14.

exception concurrent.futures.process.BrokenProcessPool

Bắt nguồn từ BrokenExecutor (trước đây là RuntimeError), lớp ngoại lệ này được nâng lên khi một trong các công nhân của ProcessPoolExecutor đã chấm dứt theo kiểu không sạch sẽ (ví dụ: nếu nó bị giết từ bên ngoài).

Added in version 3.3.