Sự khác biệt giữa luồng và mô-đun luồng trong python

Phân luồng chỉ là một trong nhiều cách có thể xây dựng các chương trình đồng thời. Trong bài viết này, chúng ta sẽ xem xét phân luồng và một vài chiến lược khác để xây dựng các chương trình đồng thời trong Python, cũng như thảo luận về cách mỗi chiến lược phù hợp trong các tình huống khác nhau

Show

Qua

Marcus McCurdy

Marcus là một lập trình viên tài năng và xuất sắc trong lĩnh vực phát triển back-end. Tuy nhiên, anh cảm thấy thoải mái với tư cách là một full stack developer

CHIA SẺ

CHIA SẺ

Ghi chú. Theo yêu cầu phổ biến, tôi trình bày một số kỹ thuật thay thế---bao gồm cả async/await, chỉ khả dụng kể từ khi Python 3 ra đời. 5---Tôi đã thêm một số cập nhật ở cuối bài viết. Vui thích

Các cuộc thảo luận chỉ trích Python thường nói về việc khó sử dụng Python cho công việc đa luồng như thế nào, chỉ tay vào cái được gọi là khóa trình thông dịch toàn cầu (được gọi một cách trìu mến là GIL) ngăn nhiều luồng mã Python chạy đồng thời. Do đó, mô-đun đa luồng Python không hoạt động hoàn toàn theo cách bạn mong đợi nếu bạn không phải là nhà phát triển Python và bạn đến từ các ngôn ngữ khác như C++ hoặc Java. Cần phải làm rõ rằng người ta vẫn có thể viết mã bằng Python chạy đồng thời hoặc song song và tạo ra sự khác biệt rõ rệt về hiệu suất kết quả, miễn là một số điều nhất định được xem xét. Nếu bạn chưa đọc nó, tôi khuyên bạn nên xem bài viết của Eqbal Qur'an về đồng thời và song song trong Ruby tại đây trên Toptal Engineering Blog

Để chứng minh tính đồng thời trong Python, chúng tôi sẽ viết một tập lệnh nhỏ để tải xuống những hình ảnh phổ biến hàng đầu từ Imgur. Chúng tôi sẽ bắt đầu với phiên bản tải xuống hình ảnh tuần tự hoặc từng hình ảnh một. Điều kiện tiên quyết, bạn sẽ phải đăng ký một ứng dụng trên Imgur. Nếu bạn chưa có tài khoản Imgur, vui lòng tạo một tài khoản trước

Các tập lệnh trong các ví dụ đa luồng Python này đã được thử nghiệm với Python 3. 6. 4. Với một số thay đổi, chúng cũng nên chạy với Python 2—urllib là thứ đã thay đổi nhiều nhất giữa hai phiên bản Python này

Bắt đầu với đa luồng Python

Hãy để chúng tôi bắt đầu bằng cách tạo một mô-đun Python, có tên là

import json
import logging
import os
from pathlib import Path
from urllib.request import urlopen, Request

logger = logging.getLogger(__name__)

types = {'image/jpeg', 'image/png'}


def get_links(client_id):
    headers = {'Authorization': 'Client-ID {}'.format(client_id)}
    req = Request('https://api.imgur.com/3/gallery/random/random/', headers=headers, method='GET')
    with urlopen(req) as resp:
        data = json.loads(resp.read().decode('utf-8'))
    return [item['link'] for item in data['data'] if 'type' in item and item['type'] in types]


def download_link(directory, link):
    download_path = directory / os.path.basename(link)
    with urlopen(link) as image, download_path.open('wb') as f:
        f.write(image.read())
    logger.info('Downloaded %s', link)


def setup_download_dir():
    download_dir = Path('images')
    if not download_dir.exists():
        download_dir.mkdir()
    return download_dir
3. Tệp này sẽ chứa tất cả các chức năng cần thiết để tìm nạp danh sách hình ảnh và tải chúng xuống. Chúng tôi sẽ chia các chức năng này thành ba chức năng riêng biệt

  • import logging
    import os
    from time import time
    
    from download import setup_download_dir, get_links, download_link
    
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    
    def main():
        ts = time()
        client_id = os.getenv('IMGUR_CLIENT_ID')
        if not client_id:
            raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
        download_dir = setup_download_dir()
        links = get_links(client_id)
        for link in links:
            download_link(download_dir, link)
        logging.info('Took %s seconds', time() - ts)
    
    if __name__ == '__main__':
        main()
    
    0
  • import logging
    import os
    from time import time
    
    from download import setup_download_dir, get_links, download_link
    
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    
    def main():
        ts = time()
        client_id = os.getenv('IMGUR_CLIENT_ID')
        if not client_id:
            raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
        download_dir = setup_download_dir()
        links = get_links(client_id)
        for link in links:
            download_link(download_dir, link)
        logging.info('Took %s seconds', time() - ts)
    
    if __name__ == '__main__':
        main()
    
    1
  • import logging
    import os
    from time import time
    
    from download import setup_download_dir, get_links, download_link
    
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    
    def main():
        ts = time()
        client_id = os.getenv('IMGUR_CLIENT_ID')
        if not client_id:
            raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
        download_dir = setup_download_dir()
        links = get_links(client_id)
        for link in links:
            download_link(download_dir, link)
        logging.info('Took %s seconds', time() - ts)
    
    if __name__ == '__main__':
        main()
    
    2

Chức năng thứ ba,

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
2, sẽ được sử dụng để tạo thư mục đích tải xuống nếu nó chưa tồn tại

API của Imgur yêu cầu các yêu cầu HTTP mang tiêu đề

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
4 với ID ứng dụng khách. Bạn có thể tìm ID khách hàng này từ bảng điều khiển của ứng dụng mà bạn đã đăng ký trên Imgur và phản hồi sẽ được mã hóa JSON. Chúng ta có thể sử dụng thư viện JSON chuẩn của Python để giải mã nó. Tải xuống hình ảnh thậm chí còn đơn giản hơn, vì tất cả những gì bạn phải làm là tìm nạp hình ảnh theo URL của nó và ghi nó vào một tệp

Đây là những gì kịch bản trông giống như

import json
import logging
import os
from pathlib import Path
from urllib.request import urlopen, Request

logger = logging.getLogger(__name__)

types = {'image/jpeg', 'image/png'}


def get_links(client_id):
    headers = {'Authorization': 'Client-ID {}'.format(client_id)}
    req = Request('https://api.imgur.com/3/gallery/random/random/', headers=headers, method='GET')
    with urlopen(req) as resp:
        data = json.loads(resp.read().decode('utf-8'))
    return [item['link'] for item in data['data'] if 'type' in item and item['type'] in types]


def download_link(directory, link):
    download_path = directory / os.path.basename(link)
    with urlopen(link) as image, download_path.open('wb') as f:
        f.write(image.read())
    logger.info('Downloaded %s', link)


def setup_download_dir():
    download_dir = Path('images')
    if not download_dir.exists():
        download_dir.mkdir()
    return download_dir

Tiếp theo, chúng ta sẽ cần viết một mô-đun sẽ sử dụng các chức năng này để tải xuống từng hình ảnh một. Chúng tôi sẽ đặt tên này là

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
5. Điều này sẽ chứa chức năng chính của phiên bản ngây thơ đầu tiên của trình tải xuống hình ảnh Imgur. Mô-đun sẽ truy xuất ID ứng dụng khách Imgur trong biến môi trường
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
6. Nó sẽ gọi
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
2 để tạo thư mục đích tải xuống. Cuối cùng, nó sẽ tìm nạp một danh sách các hình ảnh bằng cách sử dụng chức năng
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
0, lọc ra tất cả các URL của GIF và album, sau đó sử dụng
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
1 để tải xuống và lưu từng hình ảnh đó vào đĩa. Đây là những gì
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
5 trông giống như

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()

Trên máy tính xách tay của tôi, tập lệnh này mất 19. 4 giây để tải xuống 91 hình ảnh. Xin lưu ý rằng những con số này có thể thay đổi tùy theo mạng bạn đang sử dụng. 19. 4 giây không quá dài, nhưng nếu chúng ta muốn tải thêm ảnh thì sao? . Với trung bình là 0. 2 giây cho mỗi ảnh, 900 ảnh sẽ mất khoảng 3 phút. Đối với 9000 bức ảnh, sẽ mất 30 phút. Tin tốt là bằng cách giới thiệu đồng thời hoặc song song, chúng ta có thể tăng tốc độ này lên đáng kể

Tất cả các ví dụ về mã tiếp theo sẽ chỉ hiển thị các câu lệnh nhập mới và dành riêng cho các ví dụ đó. Để thuận tiện, bạn có thể tìm thấy tất cả các tập lệnh Python này trong kho lưu trữ GitHub này

Tính song song và đồng thời trong Python. Ví dụ đa luồng

Luồng là một trong những cách tiếp cận nổi tiếng nhất để đạt được tính song song và đồng thời trong Python. Luồng là một tính năng thường được cung cấp bởi hệ điều hành. Các luồng nhẹ hơn các quy trình và chia sẻ cùng một không gian bộ nhớ

Python multithreading memory model

Trong ví dụ đa luồng Python này, chúng tôi sẽ viết một mô-đun mới để thay thế

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
5. Mô-đun này sẽ tạo một nhóm gồm tám luồng, tạo thành tổng cộng chín luồng bao gồm cả luồng chính. Tôi đã chọn tám luồng công nhân vì máy tính của tôi có tám lõi CPU và một luồng công nhân trên mỗi lõi có vẻ là một con số tốt cho số lượng luồng chạy cùng một lúc. Trên thực tế, con số này được chọn cẩn thận hơn nhiều dựa trên các yếu tố khác, chẳng hạn như các ứng dụng và dịch vụ khác đang chạy trên cùng một máy

Điều này gần giống như lớp trước, ngoại trừ việc bây giờ chúng ta có một lớp mới,

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
42, là hậu duệ của lớp Python
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
43. Phương thức chạy đã bị ghi đè, chạy một vòng lặp vô hạn. Trên mỗi lần lặp lại, nó gọi
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
44 để thử và tìm nạp một URL từ hàng đợi an toàn cho luồng. Nó chặn cho đến khi có một mục trong hàng đợi để nhân viên xử lý. Khi worker nhận được một mục từ hàng đợi, nó sẽ gọi phương thức
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
1 tương tự đã được sử dụng trong tập lệnh trước đó để tải hình ảnh xuống thư mục hình ảnh. Sau khi tải xuống xong, nhân viên báo hiệu cho hàng đợi rằng nhiệm vụ đó đã hoàn thành. Điều này rất quan trọng, bởi vì Hàng đợi theo dõi có bao nhiêu tác vụ được xử lý. Cuộc gọi đến
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
46 sẽ chặn luồng chính mãi mãi nếu công nhân không báo hiệu rằng họ đã hoàn thành nhiệm vụ

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
4

Chạy tập lệnh ví dụ đa luồng Python này trên cùng một máy được sử dụng trước đó dẫn đến thời gian tải xuống là 4. 1 giây. Đó là 4. Nhanh hơn 7 lần so với ví dụ trước. Mặc dù điều này nhanh hơn nhiều, nhưng điều đáng nói là chỉ có một luồng được thực thi tại một thời điểm trong suốt quá trình này do GIL. Do đó, mã này đồng thời nhưng không song song. Lý do nó vẫn nhanh hơn là vì đây là tác vụ bị ràng buộc IO. Bộ xử lý hầu như không đổ mồ hôi khi tải xuống những hình ảnh này và phần lớn thời gian dành cho việc chờ mạng. Đây là lý do tại sao đa luồng Python có thể giúp tăng tốc độ lớn. Bộ xử lý có thể chuyển đổi giữa các luồng bất cứ khi nào một trong số chúng sẵn sàng thực hiện một số công việc. Sử dụng mô-đun luồng trong Python hoặc bất kỳ ngôn ngữ được giải thích nào khác với GIL thực sự có thể dẫn đến giảm hiệu suất. Nếu mã của bạn đang thực hiện một tác vụ bị ràng buộc bởi CPU, chẳng hạn như giải nén các tệp gzip, thì việc sử dụng mô-đun

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
47 sẽ dẫn đến thời gian thực thi chậm hơn. Đối với các tác vụ ràng buộc CPU và thực thi song song thực sự, chúng ta có thể sử dụng mô-đun đa xử lý

Mặc dù triển khai Python tham chiếu thực tế—CPython–có GIL, nhưng điều này không đúng với tất cả các triển khai Python. Ví dụ: IronPython, một triển khai Python sử dụng. NET framework, không có GIL và Jython, triển khai dựa trên Java cũng vậy. Bạn có thể tìm thấy danh sách triển khai Python đang hoạt động tại đây

Có liên quan. Mẹo và phương pháp hay nhất về Python của Toptal Developers

Đa xử lý Python. Sinh sản nhiều quá trình

Mô-đun đa xử lý Python dễ thả vào hơn mô-đun luồng, vì chúng ta không cần thêm một lớp như ví dụ đa luồng Python. Những thay đổi duy nhất chúng ta cần thực hiện là trong chức năng chính

Python multiprocessing tutorial: Modules

Để sử dụng nhiều quy trình, chúng tôi tạo một

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
48 đa xử lý. Với phương thức bản đồ mà nó cung cấp, chúng tôi sẽ chuyển danh sách URL tới nhóm, từ đó sẽ sinh ra tám quy trình mới và sử dụng từng quy trình để tải xuống hình ảnh song song. Đây là sự song song thực sự, nhưng nó đi kèm với một chi phí. Toàn bộ bộ nhớ của tập lệnh được sao chép vào từng quy trình con được sinh ra. Trong ví dụ đơn giản này, nó không phải là vấn đề lớn, nhưng nó có thể dễ dàng trở thành chi phí nghiêm trọng đối với các chương trình không tầm thường

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
2

Phân phối cho nhiều công nhân

Mặc dù các mô-đun đa luồng và đa xử lý của Python rất phù hợp với các tập lệnh đang chạy trên máy tính cá nhân của bạn, nhưng bạn nên làm gì nếu muốn công việc được thực hiện trên một máy khác hoặc bạn cần mở rộng quy mô hơn CPU trên một máy . Nếu bạn có một số tác vụ chạy dài, bạn không muốn tạo ra một loạt các quy trình phụ hoặc luồng trên cùng một máy cần chạy phần còn lại của mã ứng dụng của bạn. Điều này sẽ làm giảm hiệu suất của ứng dụng cho tất cả người dùng của bạn. Điều tuyệt vời là có thể chạy những công việc này trên một máy khác hoặc nhiều máy khác

Một thư viện Python tuyệt vời cho nhiệm vụ này là RQ, một thư viện rất đơn giản nhưng mạnh mẽ. Trước tiên, bạn liệt kê một hàm và các đối số của nó bằng thư viện. Điều này lựa chọn biểu diễn lệnh gọi hàm, sau đó được thêm vào danh sách Redis. Ghi danh vào công việc là bước đầu tiên, nhưng sẽ không làm gì cả. Chúng tôi cũng cần ít nhất một nhân viên lắng nghe hàng đợi công việc đó

Model of the RQ Python queue library

Bước đầu tiên là cài đặt và chạy máy chủ Redis trên máy tính của bạn hoặc có quyền truy cập vào máy chủ Redis đang chạy. Sau đó, chỉ có một vài thay đổi nhỏ được thực hiện đối với mã hiện tại. Trước tiên, chúng tôi tạo một phiên bản của Hàng đợi RQ và chuyển cho nó một phiên bản của máy chủ Redis từ thư viện redis-py. Sau đó, thay vì chỉ gọi phương thức

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
1 của chúng tôi, chúng tôi gọi
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
20. Phương thức enqueue lấy một hàm làm đối số đầu tiên của nó, sau đó bất kỳ đối số hoặc đối số từ khóa nào khác được chuyển cùng với hàm đó khi công việc thực sự được thực thi

Một bước cuối cùng chúng ta cần làm là khởi động một số công nhân. RQ cung cấp tập lệnh tiện dụng để chạy công nhân trên hàng đợi mặc định. Chỉ cần chạy

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
21 trong cửa sổ đầu cuối và nó sẽ bắt đầu một nhân viên lắng nghe trên hàng đợi mặc định. Vui lòng đảm bảo rằng thư mục làm việc hiện tại của bạn giống với nơi lưu trữ tập lệnh. Nếu bạn muốn nghe một hàng đợi khác, bạn có thể chạy
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
22 và nó sẽ nghe hàng đợi có tên đó. Điều tuyệt vời về RQ là miễn là bạn có thể kết nối với Redis, bạn có thể chạy bao nhiêu công nhân tùy thích trên bao nhiêu máy khác nhau tùy thích; . Đây là nguồn cho phiên bản RQ

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
7

Tuy nhiên, RQ không phải là giải pháp hàng đợi công việc Python duy nhất. RQ rất dễ sử dụng và đáp ứng rất tốt các trường hợp sử dụng đơn giản, nhưng nếu cần các tùy chọn nâng cao hơn, thì có thể sử dụng các giải pháp hàng đợi Python 3 khác (chẳng hạn như Celery)

Đa xử lý so với. Đa luồng trong Python

Nếu mã của bạn bị ràng buộc IO, cả đa xử lý và đa luồng trong Python sẽ phù hợp với bạn. Đa xử lý Python dễ thả vào hơn so với luồng nhưng có chi phí bộ nhớ cao hơn. Nếu mã của bạn bị ràng buộc bởi CPU, đa xử lý rất có thể sẽ là lựa chọn tốt hơn—đặc biệt nếu máy mục tiêu có nhiều lõi hoặc CPU. Đối với các ứng dụng web và khi bạn cần mở rộng quy mô công việc trên nhiều máy, RQ sẽ phù hợp hơn với bạn

Có liên quan. Trở nên cao cấp hơn. Tránh 10 lỗi phổ biến nhất mà các lập trình viên Python mắc phải


 

Cập nhật

Một cái gì đó mới kể từ Python 3. 2 không được đề cập đến trong bài viết gốc là gói

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
23. Gói này cung cấp một cách khác để sử dụng song song và đồng thời với Python

Trong bài viết gốc, tôi đã đề cập rằng mô-đun đa xử lý Python sẽ dễ dàng đưa vào mã hiện có hơn mô-đun phân luồng. Điều này là do mô-đun luồng Python 3 yêu cầu phân lớp con lớp

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
43 và cũng tạo một
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
26 để các luồng theo dõi hoạt động

Sử dụng đồng thời. tương lai. ThreadPoolExecutor làm cho mã ví dụ luồng Python gần giống với mô-đun đa xử lý

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
2

Bây giờ chúng tôi đã tải xuống tất cả những hình ảnh này bằng Python

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
27 của mình, chúng tôi có thể sử dụng chúng để kiểm tra tác vụ liên quan đến CPU. Chúng tôi có thể tạo các phiên bản hình thu nhỏ của tất cả các hình ảnh trong cả tập lệnh đơn luồng, xử lý đơn và sau đó thử nghiệm giải pháp dựa trên đa xử lý

Chúng tôi sẽ sử dụng thư viện Gối để xử lý việc thay đổi kích thước của hình ảnh

Đây là kịch bản ban đầu của chúng tôi

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
4

Tập lệnh này lặp lại trên các đường dẫn trong thư mục

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
28 và với mỗi đường dẫn, nó sẽ chạy hàm create_thumbnail. Chức năng này sử dụng Gối để mở hình ảnh, tạo hình thu nhỏ và lưu hình ảnh mới, nhỏ hơn có cùng tên với hình gốc nhưng có thêm
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
29 vào tên

Chạy tập lệnh này trên 160 hình ảnh với tổng số 36 triệu mất 2. 32 giây. Hãy xem liệu chúng ta có thể tăng tốc độ này bằng cách sử dụng ProcessPoolExecutor không

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
7

Phương thức

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
70 giống với tập lệnh cuối cùng. Sự khác biệt chính là việc tạo ra một
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
71. Phương thức bản đồ của người thực thi được sử dụng để tạo các hình thu nhỏ song song. Theo mặc định,
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
71 tạo một quy trình con cho mỗi CPU. Chạy tập lệnh này trên cùng 160 hình ảnh mất 1. 05 giây—2. nhanh gấp 2 lần

Không đồng bộ/Đang chờ (Python 3. 5+ chỉ)

Một trong những mục được yêu cầu nhiều nhất trong các nhận xét về bài viết gốc là ví dụ sử dụng mô-đun asyncio của Python 3. So với các ví dụ khác, có một số cú pháp Python mới có thể mới đối với hầu hết mọi người và cũng có một số khái niệm mới. Một lớp phức tạp bổ sung đáng tiếc là do mô-đun

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
73 tích hợp sẵn của Python không đồng bộ. Chúng tôi sẽ cần sử dụng thư viện HTTP async để nhận được đầy đủ lợi ích của asyncio. Đối với điều này, chúng tôi sẽ sử dụng aiohttp

Hãy nhảy ngay vào mã và một lời giải thích chi tiết hơn sẽ theo sau

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
2

Có khá nhiều thứ để giải nén ở đây. Hãy bắt đầu với điểm vào chính của chương trình. Điều mới đầu tiên chúng tôi làm với mô-đun asyncio là lấy vòng lặp sự kiện. Vòng lặp sự kiện xử lý tất cả mã không đồng bộ. Sau đó, vòng lặp được chạy cho đến khi hoàn thành và chuyển hàm

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
74. Có một phần cú pháp mới trong định nghĩa của main.
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
75. Bạn cũng sẽ nhận thấy
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
76 và
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
77

Cú pháp async/await đã được giới thiệu trong PEP492. Cú pháp

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
75 đánh dấu một hàm là một coroutine. Bên trong, các coroutine dựa trên các trình tạo Python, nhưng không hoàn toàn giống nhau. Các coroutine trả về một đối tượng coroutine tương tự như cách các trình tạo trả về một đối tượng trình tạo. Khi bạn có một coroutine, bạn sẽ nhận được kết quả của nó với biểu thức
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
76. Khi một quy trình đăng ký gọi
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
76, việc thực hiện quy trình đăng ký bị tạm dừng cho đến khi quá trình chờ đợi hoàn tất. Việc đình chỉ này cho phép các công việc khác được hoàn thành trong khi coroutine bị đình chỉ “chờ đợi” một số kết quả. Nói chung, kết quả này sẽ là một số loại I/O như yêu cầu cơ sở dữ liệu hoặc trong trường hợp của chúng tôi là yêu cầu HTTP

Chức năng

import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
1 phải được thay đổi khá nhiều. Trước đây, chúng tôi đã dựa vào
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
73 để thực hiện phần lớn công việc đọc hình ảnh cho chúng tôi. Bây giờ, để cho phép phương thức của chúng tôi hoạt động chính xác với mô hình lập trình không đồng bộ, chúng tôi đã giới thiệu một vòng lặp
import logging
import os
from time import time

from download import setup_download_dir, get_links, download_link

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main():
    ts = time()
    client_id = os.getenv('IMGUR_CLIENT_ID')
    if not client_id:
        raise Exception("Couldn't find IMGUR_CLIENT_ID environment variable!")
    download_dir = setup_download_dir()
    links = get_links(client_id)
    for link in links:
        download_link(download_dir, link)
    logging.info('Took %s seconds', time() - ts)

if __name__ == '__main__':
    main()
23 đọc các đoạn hình ảnh tại một thời điểm và tạm dừng thực thi trong khi chờ I/O hoàn tất. Điều này cho phép vòng lặp sự kiện lặp qua việc tải xuống các hình ảnh khác nhau vì mỗi hình ảnh đều có sẵn dữ liệu mới trong quá trình tải xuống

Nên có một—Tốt nhất là chỉ có một—Cách rõ ràng để làm điều đó

Mặc dù zen của Python cho chúng ta biết nên có một cách rõ ràng để làm điều gì đó, nhưng có nhiều cách trong Python để đưa đồng thời vào các chương trình của chúng ta. Phương pháp tốt nhất để chọn sẽ phụ thuộc vào trường hợp sử dụng cụ thể của bạn. Mô hình không đồng bộ mở rộng quy mô tốt hơn cho khối lượng công việc đồng thời cao (như máy chủ web) so với phân luồng hoặc đa xử lý, nhưng nó yêu cầu mã của bạn (và các phần phụ thuộc) không đồng bộ để có thể hưởng lợi đầy đủ

Hy vọng rằng các ví dụ về đa luồng Python trong bài viết này—và bản cập nhật—sẽ chỉ cho bạn đi đúng hướng để bạn có ý tưởng về nơi tìm kiếm trong thư viện chuẩn Python nếu bạn cần giới thiệu đồng thời vào các chương trình của mình

Hiểu những điều cơ bản

Chuỗi trong Python là gì?

Một chủ đề là một quá trình hoặc nhiệm vụ nhẹ. Chuỗi là một cách để thêm đồng thời vào chương trình của bạn. Nếu ứng dụng Python của bạn đang sử dụng nhiều luồng và bạn xem xét các quy trình đang chạy trên hệ điều hành của mình, bạn sẽ chỉ thấy một mục duy nhất cho tập lệnh của mình mặc dù nó đang chạy nhiều luồng

Đa luồng là gì?

Đa luồng (đôi khi chỉ đơn giản là "phân luồng") là khi một chương trình tạo nhiều luồng với chu kỳ thực thi giữa chúng, do đó, một tác vụ chạy lâu hơn không chặn tất cả các tác vụ khác. Điều này hoạt động tốt cho các nhiệm vụ có thể được chia thành các nhiệm vụ nhỏ hơn, sau đó mỗi nhiệm vụ có thể được trao cho một luồng để hoàn thành

Sự khác biệt giữa luồng Python và đa xử lý là gì?

Với luồng, đồng thời đạt được bằng cách sử dụng nhiều luồng, nhưng do GIL, chỉ có một luồng có thể chạy tại một thời điểm. Trong đa xử lý, quy trình ban đầu được chia nhỏ quy trình thành nhiều quy trình con bỏ qua GIL. Mỗi tiến trình con sẽ có một bản sao toàn bộ bộ nhớ của chương trình

Đa luồng và đa xử lý trong Python có liên quan như thế nào?

Cả đa luồng và đa xử lý đều cho phép mã Python chạy đồng thời. Chỉ đa xử lý mới cho phép mã của bạn thực sự song song. Tuy nhiên, nếu mã của bạn nặng về IO (như yêu cầu HTTP), thì đa luồng vẫn có thể tăng tốc mã của bạn

Thẻ

PythonConcurrencyParallelismThreadingĐa xử lý

Người làm việc tự do? Tìm công việc tiếp theo của bạn.

Việc làm Lập trình viên Python

Xem thông tin đầy đủ

Marcus McCurdy

Kỹ sư phần mềm tự do

Giới thiệu về tác giả

Marcus có bằng cử nhân kỹ thuật máy tính và bằng thạc sĩ khoa học máy tính. Anh ấy là một lập trình viên tài năng và xuất sắc nhất trong lĩnh vực phát triển back-end, nhưng anh ấy cũng hoàn toàn thoải mái khi tạo ra các sản phẩm bóng bẩy với tư cách là một nhà phát triển full-stack

Thuê Marcus

Bình luận

jorjun

Muốn xem một ví dụ sử dụng mô-đun asyncio mới. Ngoài ra, Gevent hoạt động kỳ diệu đối với loại sự cố đồng thời bị ràng buộc I/O này nếu bạn phải gắn bó với python 2. Thực sự không cần sử dụng luồng hoặc đa xử lý - luồng xanh có thể là cách tốt nhất

jorjun

Muốn xem một ví dụ sử dụng mô-đun asyncio mới. Ngoài ra, Gevent hoạt động kỳ diệu đối với loại sự cố đồng thời bị ràng buộc I/O này nếu bạn phải gắn bó với python 2. Thực sự không cần sử dụng luồng hoặc đa xử lý - luồng xanh có thể là cách tốt nhất

Marcus McCurdy

Mô-đun asyncio sẽ là một ví dụ khá quan trọng vì mã urllib cơ bản không được thiết lập để sử dụng các kết nối không đồng bộ. Bạn có thể xem một ví dụ ở đây https. // tài liệu. con trăn. org/3/library/asyncio-stream. html#get-http-headers của tìm nạp tiêu đề. Tôi định chạm vào Gevent, nhưng nó không hoạt động với Python 3 vào lúc này

Marcus McCurdy

Mô-đun asyncio sẽ là một ví dụ khá quan trọng vì mã urllib cơ bản không được thiết lập để sử dụng các kết nối không đồng bộ. Bạn có thể xem một ví dụ ở đây https. // tài liệu. con trăn. org/3/library/asyncio-stream. html#get-http-headers của tìm nạp tiêu đề. Tôi định chạm vào Gevent, nhưng nó không hoạt động với Python 3 vào lúc này

Mariano Simone

Nếu mã của bạn bị ràng buộc I/O, bạn nên tăng số lượng luồng dữ liệu mà một quy trình quản lý bằng I/O không đồng bộ. Tạo một luồng/rẽ một quy trình chỉ để xử lý các kết nối mới là một sự lãng phí tài nguyên khủng khiếp. Bây giờ, nếu bạn đang thực hiện các hoạt động chuyên sâu về CPU, thì rõ ràng việc ném nhiều lõi hơn vào vấn đề là điều hợp lý.

Mariano Simone

Nếu mã của bạn bị ràng buộc I/O, bạn nên tăng số lượng luồng dữ liệu mà một quy trình quản lý bằng I/O không đồng bộ. Tạo một luồng/rẽ một quy trình chỉ để xử lý các kết nối mới là một sự lãng phí tài nguyên khủng khiếp. Bây giờ, nếu bạn đang thực hiện các hoạt động chuyên sâu về CPU, thì rõ ràng việc ném nhiều lõi hơn vào vấn đề là điều hợp lý.

Mariano Simone

Btw, số lượng công việc và chất lượng của bài đăng rất ấn tượng. Dude công việc tốt

Mariano Simone

Btw, số lượng công việc và chất lượng của bài đăng rất ấn tượng. Dude công việc tốt

jorjun

tôi hiểu rồi. Mô-đun aiohttp có vẻ đầy hứa hẹn. http. // geekgirl. io/concurrent-http-requests-with-python3-and-asyncio/

jorjun

tôi hiểu rồi. Mô-đun aiohttp có vẻ đầy hứa hẹn. http. // geekgirl. io/concurrent-http-requests-with-python3-and-asyncio/

Marcus McCurdy

Bạn đúng rằng cách tiếp cận đồng thời/song song phụ thuộc vào việc mã cơ bản có phải là IO so với. CPU bị ràng buộc và tôi chạm vào điều này một chút trong bài viết. Tôi muốn giữ cho bài viết đơn giản nhất có thể và vẫn thể hiện các tùy chọn khác nhau có sẵn trong Python 3. Tôi cảm thấy rằng việc bao gồm cả các ví dụ về giới hạn IO và giới hạn CPU sẽ làm bài viết trở nên cồng kềnh, nhưng tôi có đề cập đến một ví dụ về tác vụ giới hạn CPU trong bài viết. Tôi thực sự muốn viết bài này bằng Python 3 vì tôi cảm thấy không có nhiều tài nguyên cho nó. Tôi cũng muốn bao gồm IO không đồng bộ bằng cách sử dụng gevent, nhưng gevent không hỗ trợ Python 3. Tôi quyết định sử dụng một bài viết Python 3 thuần túy thay vì bao gồm một số ví dụ hoạt động trong Python 3 và một số hoạt động trong Python 2

Marcus McCurdy

Bạn đúng rằng cách tiếp cận đồng thời/song song phụ thuộc vào việc mã cơ bản có phải là IO so với. CPU bị ràng buộc và tôi chạm vào điều này một chút trong bài viết. Tôi muốn giữ cho bài viết đơn giản nhất có thể và vẫn thể hiện các tùy chọn khác nhau có sẵn trong Python 3. Tôi cảm thấy rằng việc bao gồm cả các ví dụ về giới hạn IO và giới hạn CPU sẽ làm bài viết trở nên cồng kềnh, nhưng tôi có đề cập đến một ví dụ về tác vụ giới hạn CPU trong bài viết. Tôi thực sự muốn viết bài này bằng Python 3 vì tôi cảm thấy không có nhiều tài nguyên cho nó. Tôi cũng muốn bao gồm IO không đồng bộ bằng cách sử dụng gevent, nhưng gevent không hỗ trợ Python 3. Tôi quyết định sử dụng một bài viết Python 3 thuần túy thay vì bao gồm một số ví dụ hoạt động trong Python 3 và một số hoạt động trong Python 2

Marcus McCurdy

Cảm ơn lời khen và bình luận khác của bạn

Marcus McCurdy

Cảm ơn lời khen và bình luận khác của bạn

Eki Eqbal

Bài viết hay, tiếp tục phát huy. Chúc mừng

Eki Eqbal

Bài viết hay, tiếp tục phát huy. Chúc mừng

rockqi

bài viết hay với hình ảnh thú vị, cảm ơn

rockqi

bài viết hay với hình ảnh thú vị, cảm ơn

Zero_NzYme

bài viết rất hay. Sẽ thử các tùy chọn redis và cần tây. Rất tuyệt

Zero_NzYme

bài viết rất hay. Sẽ thử các tùy chọn redis và cần tây. Rất tuyệt

Jon

Xin chào, bạn có thể cung cấp một số thông tin chi tiết về cách một người nào đó có thể sử dụng tính năng đa xử lý để thực hiện các chức năng khác nhau không?. g. chức năng đầu tiên là đọc các tệp csv đã nén vào bộ nhớ và chức năng thứ hai hợp nhất các tệp csv đó theo cùng một thứ tự. Bằng cách này, chức năng 2 vẫn đang hợp nhất tệp 1 và tệp 2, tệp 3 đang được đọc vào bộ nhớ. Tương tự như cách một cửa hàng bánh sandwich có thể có nhiều công nhân làm việc trên cùng một chiếc bánh mì khi họ trải qua các giai đoạn sản xuất khác nhau

Jon

Xin chào, bạn có thể cung cấp một số thông tin chi tiết về cách một người nào đó có thể sử dụng tính năng đa xử lý để thực hiện các chức năng khác nhau không?. g. chức năng đầu tiên là đọc các tệp csv đã nén vào bộ nhớ và chức năng thứ hai hợp nhất các tệp csv đó theo cùng một thứ tự. Bằng cách này, chức năng 2 vẫn đang hợp nhất tệp 1 và tệp 2, tệp 3 đang được đọc vào bộ nhớ. Tương tự như cách một cửa hàng bánh sandwich có thể có nhiều công nhân làm việc trên cùng một chiếc bánh mì khi họ trải qua các giai đoạn sản xuất khác nhau

Ashwin Nanjappa

Bài báo hay. Tuy nhiên, nó không được đề cập phải làm gì nếu mã của bạn bị ràng buộc bởi CPU, dữ liệu lớn (đa xử lý không còn nữa) và không phải là một ứng dụng web. Đây là điển hình của các ứng dụng khoa học. Bài báo ít nhất nên đề cập trong phần kết luận rằng điều này hiện không thể được giải quyết trong CPython một cách hiệu quả

Ashwin Nanjappa

Bài báo hay. Tuy nhiên, nó không được đề cập phải làm gì nếu mã của bạn bị ràng buộc bởi CPU, dữ liệu lớn (đa xử lý không còn nữa) và không phải là một ứng dụng web. Đây là điển hình của các ứng dụng khoa học. Bài báo ít nhất nên đề cập trong phần kết luận rằng điều này hiện không thể được giải quyết trong CPython một cách hiệu quả

Anon Omus

Hiển thị một kỹ thuật mà không cung cấp thông tin cần thiết để sử dụng đúng kỹ thuật khó có thể được coi là phình to. Nó chỉ là lười biếng. . /

Anon Omus

Hiển thị một kỹ thuật mà không cung cấp thông tin cần thiết để sử dụng đúng kỹ thuật khó có thể được coi là phình to. Nó chỉ là lười biếng. . /

Andrew Franklin

Là một người không biết nhiều về đồng thời và song song trong python, đây có vẻ là một nơi tốt để bắt đầu. Cảm ơn cho hướng dẫn này. Thật không may, tôi cũng không biết nhiều về urllib và tải hình ảnh từ imgur. Đôi khi, các mã này không chạy cho tôi và tôi gặp lỗi sau. "urllib. lỗi. Lỗi HTTP. Lỗi HTTP 403. Quyền bị từ chối" Rất không nhất quán khi tôi nhận được lỗi và đôi khi mã chạy mà không gặp trở ngại nào. Có ai biết cách sửa lỗi này để nó chạy mọi lúc không?

Andrew Franklin

Là một người không biết nhiều về đồng thời và song song trong python, đây có vẻ là một nơi tốt để bắt đầu. Cảm ơn cho hướng dẫn này. Thật không may, tôi cũng không biết nhiều về urllib và tải hình ảnh từ imgur. Đôi khi, các mã này không chạy cho tôi và tôi gặp lỗi sau. "urllib. lỗi. Lỗi HTTP. Lỗi HTTP 403. Quyền bị từ chối" Rất không nhất quán khi tôi nhận được lỗi và đôi khi mã chạy mà không gặp trở ngại nào. Có ai biết cách sửa lỗi này để nó chạy mọi lúc không?

Eric O LEBIGOT (EOL)

Làm tốt lắm. hiếm thấy những blogger viết mã Python giỏi. . ) Bây giờ, bạn chia sẻ tốc độ tăng tốc thu được với chủ đề. bạn nhận được gì với đa xử lý?

Eric O LEBIGOT (EOL)

Làm tốt lắm. hiếm thấy những blogger viết mã Python giỏi. . ) Bây giờ, bạn chia sẻ tốc độ tăng tốc thu được với chủ đề. bạn nhận được gì với đa xử lý?

mattias

Xin chào, Phần phân luồng cho số lượng CPU không có ý nghĩa gì. Vì nó chỉ chạy trên một lõi CPU vì các luồng python không phải là luồng os thực nên không liên quan đến số lượng lõi có sẵn

mattias

Xin chào, Phần phân luồng cho số lượng CPU không có ý nghĩa gì. Vì nó chỉ chạy trên một lõi CPU vì các luồng python không phải là luồng os thực nên không liên quan đến số lượng lõi có sẵn

Yuval Baror

Bai bao tuyệt vơi, cảm ơn vi đa chia sẻ. Bạn có thể cung cấp một số chi tiết về thời gian chạy của các giải pháp đa xử lý và RQ so với các giải pháp ban đầu và theo luồng không?

Yuval Baror

Bai bao tuyệt vơi, cảm ơn vi đa chia sẻ. Bạn có thể cung cấp một số chi tiết về thời gian chạy của các giải pháp đa xử lý và RQ so với các giải pháp ban đầu và theo luồng không?

Marcus McCurdy

Bạn có thể tìm thấy mã nguồn đầy đủ của tất cả các ví dụ trong bài viết tại đây https. //github. com/volker48/python-concurrency. Tôi chưa bao giờ thấy bất kỳ lỗi 403 nào khi thử nghiệm, nhưng lỗi đó sẽ đến từ API của Imgur. Tôi không chắc bạn đang sử dụng loại mạng nào, nhưng có lẽ IP của bạn, nếu được chia sẻ, sẽ khiến bạn đạt đến một số loại giới hạn API

Marcus McCurdy

Bạn có thể tìm thấy mã nguồn đầy đủ của tất cả các ví dụ trong bài viết tại đây https. //github. com/volker48/python-concurrency. Tôi chưa bao giờ thấy bất kỳ lỗi 403 nào khi thử nghiệm, nhưng lỗi đó sẽ đến từ API của Imgur. Tôi không chắc bạn đang sử dụng loại mạng nào, nhưng có lẽ IP của bạn, nếu được chia sẻ, sẽ khiến bạn đạt đến một số loại giới hạn API

thợ xóa

Tôi cũng muốn xem kết quả này. Bạn có thể vui lòng thêm nó vào bài đăng hoặc ở đây như một câu trả lời không?

thợ xóa

Tôi cũng muốn xem kết quả này. Bạn có thể vui lòng thêm nó vào bài đăng hoặc ở đây như một câu trả lời không?

ravi

bài viết hay. Ngạc nhiên khi không thấy Gevent trong danh sách

ravi

bài viết hay. Ngạc nhiên khi không thấy Gevent trong danh sách

bjlange

+1 cho RQ. Cho đến nay, cách thân thiện với người dùng nhất mà tôi đã tìm thấy để phân phối công việc trên các máy

bjlange

+1 cho RQ. Cho đến nay, cách thân thiện với người dùng nhất mà tôi đã tìm thấy để phân phối công việc trên các máy

Nabeel Valapra

Đây là những gì tôi đang tìm kiếm. Người tuyệt vời

Nabeel Valapra

Đây là những gì tôi đang tìm kiếm. Người tuyệt vời

Jay Dreyer

Cám ơn vì cái này. Cải tiến gấp 10 lần trong tập lệnh tôi sử dụng thường xuyên. Cảm ơn

Jay Dreyer

Cám ơn vì cái này. Cải tiến gấp 10 lần trong tập lệnh tôi sử dụng thường xuyên. Cảm ơn

JEdVcM

Trong mã luồng của bạn, bạn đang chờ đợi bận rộn với "trong khi đúng" + đọc hàng đợi không chặn. Điều này không sao nếu bạn có nội dung trong hàng đợi của mình và bạn kết thúc nội dung đó ở cuối, nhưng nếu không thì nó sẽ trở thành một con lợn CPU. Chúng tôi đã có điều đó một vài tháng trước trong dự án của chúng tôi. Một điều khác, tôi chắc chắn không hiểu hoàn toàn về luồng python, nhưng ngay cả trong môi trường ràng buộc I/O, làm thế nào bạn có thể nhanh hơn nếu bạn chỉ sử dụng các lần đọc mạng đồng bộ? . Tôi bỏ lỡ điều gì?

JEdVcM

Trong mã luồng của bạn, bạn đang chờ đợi bận rộn với "trong khi đúng" + đọc hàng đợi không chặn. Điều này không sao nếu bạn có nội dung trong hàng đợi của mình và bạn kết thúc nội dung đó ở cuối, nhưng nếu không thì nó sẽ trở thành một con lợn CPU. Chúng tôi đã có điều đó một vài tháng trước trong dự án của chúng tôi. Một điều khác, tôi chắc chắn không hiểu hoàn toàn về luồng python, nhưng ngay cả trong môi trường ràng buộc I/O, làm thế nào bạn có thể nhanh hơn nếu bạn chỉ sử dụng các lần đọc mạng đồng bộ? . Tôi bỏ lỡ điều gì?

Dannnno

Theo những gì tôi nhớ lại, CPython phát hành GIL khi các luồng đang chờ sự kiện IO - tuy nhiên tôi không rõ chi tiết cụ thể về cách thức thực hiện

Dannnno

Theo những gì tôi nhớ lại, CPython phát hành GIL khi các luồng đang chờ sự kiện IO - tuy nhiên tôi không rõ chi tiết cụ thể về cách thức thực hiện

JEdVcM

Điều đó sẽ giải thích mọi thứ tốt. Tuy nhiên, tôi chưa tìm thấy gì về điều đó. Cái khác. xin lỗi, tôi đã sai. Mã này sử dụng chờ chặn

JEdVcM

Điều đó sẽ giải thích mọi thứ tốt. Tuy nhiên, tôi chưa tìm thấy gì về điều đó. Cái khác. xin lỗi, tôi đã sai. Mã này sử dụng chờ chặn

Dannnno

Tôi cũng không thể tìm thấy nơi tôi đã đọc nó ban đầu, tuy nhiên bạn có thể có mẩu tin nhỏ này "Lưu ý rằng các hoạt động có khả năng chặn hoặc chạy dài, chẳng hạn như I/O, xử lý hình ảnh và xử lý số NumPy, xảy ra bên ngoài GIL. " https. //wiki. con trăn. org/moin/GlobalInterpreterLock

Dannnno

Tôi cũng không thể tìm thấy nơi tôi đã đọc nó ban đầu, tuy nhiên bạn có thể có mẩu tin nhỏ này "Lưu ý rằng các hoạt động có khả năng chặn hoặc chạy dài, chẳng hạn như I/O, xử lý hình ảnh và xử lý số NumPy, xảy ra bên ngoài GIL. " https. //wiki. con trăn. org/moin/GlobalInterpreterLock

Arulbalan Subramani

Xin chào Marcus, Bài đăng tuyệt vời. Cảm ơn, một câu hỏi. mặc dù chúng tôi không có chủ đề nào được kiểm soát bằng cách sử dụng lớp semaphore, tại sao chúng tôi cần lớp hàng đợi để xử lý các chủ đề?

Arulbalan Subramani

Xin chào Marcus, Bài đăng tuyệt vời. Cảm ơn, một câu hỏi. mặc dù chúng tôi không có chủ đề nào được kiểm soát bằng cách sử dụng lớp semaphore, tại sao chúng tôi cần lớp hàng đợi để xử lý các chủ đề?

Quảng trường Andreu Vallbona

Trong ví dụ về Pool đa xử lý, làm thế nào để bạn kiểm soát cùng một liên kết không được tải xuống cho mọi quy trình?

Quảng trường Andreu Vallbona

Trong ví dụ về Pool đa xử lý, làm thế nào để bạn kiểm soát cùng một liên kết không được tải xuống cho mọi quy trình?

Marcus McCurdy

Its the way the map function works with the multiprocessing pool.

p.map(download, links)
Links is a list of download links. p.map calls the download function once for each link in the list. Because this is the map function on a pool object each function may run in its own process. Pool's map function works similarly to Python's built in map function. Not sure if you are familiar with it, but it might make more sense if you play around with it https://docs.python.org/2/library/functions.html#map.

Marcus McCurdy

Its the way the map function works with the multiprocessing pool.

p.map(download, links)
Links is a list of download links. p.map calls the download function once for each link in the list. Because this is the map function on a pool object each function may run in its own process. Pool's map function works similarly to Python's built in map function. Not sure if you are familiar with it, but it might make more sense if you play around with it https://docs.python.org/2/library/functions.html#map.

Mike Zang

Đây là một công việc tuyệt vời. Tôi muốn sử dụng nó cho các dự án của tôi. Tôi phân tích cú pháp từng liên kết hình ảnh một cách linh hoạt, làm cách nào tôi có thể sử dụng cách chuỗi hoặc nhóm của bạn?

Mike Zang

Đây là một công việc tuyệt vời. Tôi muốn sử dụng nó cho các dự án của tôi. Tôi phân tích cú pháp từng liên kết hình ảnh một cách linh hoạt, làm cách nào tôi có thể sử dụng cách chuỗi hoặc nhóm của bạn?

bãi cát

Cần tây là một thứ tuyệt vời để sử dụng. Nó có thể mở rộng quy mô thực sự tốt. Ngoài ra, nó có thể linh hoạt sử dụng redis hoặc rabbitmq làm nhà môi giới

bãi cát

Cần tây là một thứ tuyệt vời để sử dụng. Nó có thể mở rộng quy mô thực sự tốt. Ngoài ra, nó có thể linh hoạt sử dụng redis hoặc rabbitmq làm nhà môi giới

bia3andro

Cám ơn bạn rất nhiều về điều này. Nỗ lực đầu tiên của tôi để viết một tập lệnh python theo luồng đã dẫn đến thành công

bia3andro

Cám ơn bạn rất nhiều về điều này. Nỗ lực đầu tiên của tôi để viết một tập lệnh python theo luồng đã dẫn đến thành công

Sunda Môsê

Marcus viết rất hay. Tôi cũng là một lập trình viên python. Mặc dù tôi đã sử dụng các chức năng này đồng thời, nhưng tôi không thể viết lại chương trình bằng python vào lần tới và tôi quên luồng hoặc tham số. một lần nữa tôi giới thiệu chương trình cũ của mình để nhớ lại dòng chảy. Bạn có mẹo nào để ghi nhớ các lệnh gọi hàm và đối số này không?

Sunda Môsê

Marcus viết rất hay. Tôi cũng là một lập trình viên python. Mặc dù tôi đã sử dụng các chức năng này đồng thời, nhưng tôi không thể viết lại chương trình bằng python vào lần tới và tôi quên luồng hoặc tham số. một lần nữa tôi giới thiệu chương trình cũ của mình để nhớ lại dòng chảy. Bạn có mẹo nào để ghi nhớ các lệnh gọi hàm và đối số này không?

máy bay

Xin chào, tôi có chức năng chấp nhận đường dẫn tệp và thực hiện phân tích trên đó. Nó trả về một id cho hàng khung dữ liệu gấu trúc mà nó đã được thêm vào. Đường dẫn tệp được truyền dưới dạng một chuỗi mỗi lần, từ một chương trình khác. Theo thời gian, phân tích đã bao gồm các loại tệp khác nhau và mất một thời gian. Tôi cần triển khai đa xử lý cho phần này. Điều gì sẽ là cách tốt nhất để làm điều đó?

máy bay

Xin chào, tôi có chức năng chấp nhận đường dẫn tệp và thực hiện phân tích trên đó. Nó trả về một id cho hàng khung dữ liệu gấu trúc mà nó đã được thêm vào. Đường dẫn tệp được truyền dưới dạng một chuỗi mỗi lần, từ một chương trình khác. Theo thời gian, phân tích đã bao gồm các loại tệp khác nhau và mất một thời gian. Tôi cần triển khai đa xử lý cho phần này. Điều gì sẽ là cách tốt nhất để làm điều đó?

Will Vaughn

Vâng, mã của bạn trên github hoạt động, nhưng những gì bạn đã viết trong blog không hoạt động

Will Vaughn

Vâng, mã của bạn trên github hoạt động, nhưng những gì bạn đã viết trong blog không hoạt động

Marcus McCurdy

Mã trên github đã được cập nhật sau khi bài đăng trên blog được viết để giải thích cho một số thay đổi trong API imgur. Tôi không có quyền truy cập trực tiếp vào bài đăng trên blog như tôi làm với repo github. Phần nào của bài đăng trên blog không phù hợp với bạn? . cảm ơn sẽ

Marcus McCurdy

Mã trên github đã được cập nhật sau khi bài đăng trên blog được viết để giải thích cho một số thay đổi trong API imgur. Tôi không có quyền truy cập trực tiếp vào bài đăng trên blog như tôi làm với repo github. Phần nào của bài đăng trên blog không phù hợp với bạn? . cảm ơn sẽ

David Nguyễn

Bài báo tuyệt vời

David Nguyễn

Bài báo tuyệt vời

Rohit Malgaonkar

Chưa thử máy chủ redis nhưng đã cài đặt máy chủ python RabbitMQ và có 1 nhà sản xuất (gửi dữ liệu chuỗi được mã hóa dưới dạng JSON) và 3 người tiêu dùng cho tập lệnh ràng buộc cpu (lặp tệp csv, tìm kiếm dữ liệu JSON được giải mã do nhà sản xuất gửi) và nó giảm một nửa thời gian nhưng

Rohit Malgaonkar

Chưa thử máy chủ redis nhưng đã cài đặt máy chủ python RabbitMQ và có 1 nhà sản xuất (gửi dữ liệu chuỗi được mã hóa dưới dạng JSON) và 3 người tiêu dùng cho tập lệnh ràng buộc cpu (lặp tệp csv, tìm kiếm dữ liệu JSON được giải mã do nhà sản xuất gửi) và nó giảm một nửa thời gian nhưng

Vikas Gupta

Blog tốt về đa luồng. Cảm ơn. . )

Vikas Gupta

Blog tốt về đa luồng. Cảm ơn. . )

Dung nham Kafle

tuyệt vời

Dung nham Kafle

tuyệt vời

Heron Rossi

bài viết rất hay. Mục đích của công nhân là gì. daemon = True cho ví dụ cụ thể này? . tham gia()) ?

Heron Rossi

bài viết rất hay. Mục đích của công nhân là gì. daemon = True cho ví dụ cụ thể này? . tham gia()) ?

Daniel Nuriev

tôi đồng ý. Tác giả và độc giả thích bài viết này không nhận ra rằng các luồng không phải là luồng của hệ điều hành mà là các chuỗi mã byte Python chạy trên một luồng hệ điều hành. Python VM thực thi từng luồng tối đa 10 mili giây và chuyển sang luồng tiếp theo. Sự cải tiến là do mã này thực hiện IO. Không có IO, hiệu suất sẽ kém hơn

Daniel Nuriev

tôi đồng ý. Tác giả và độc giả thích bài viết này không nhận ra rằng các luồng không phải là luồng của hệ điều hành mà là các chuỗi mã byte Python chạy trên một luồng hệ điều hành. Python VM thực thi từng luồng tối đa 10 mili giây và chuyển sang luồng tiếp theo. Sự cải tiến là do mã này thực hiện IO. Không có IO, hiệu suất sẽ kém hơn

mattias

Tôi định nói với bạn rằng cả hai bạn đều sai khi tôi nhận ra rằng tôi đã viết tuyên bố ban đầu. Dù sao, các luồng python là các luồng thực, được gắn với cùng một PPID, nhưng chỉ một luồng được thực thi tại một thời điểm bất kể số lượng lõi có sẵn do khóa interpeter toàn cầu. Có cái đó

mattias

Tôi định nói với bạn rằng cả hai bạn đều sai khi tôi nhận ra rằng tôi đã viết tuyên bố ban đầu. Dù sao, các luồng python là các luồng thực, được gắn với cùng một PPID, nhưng chỉ một luồng được thực thi tại một thời điểm bất kể số lượng lõi có sẵn do khóa interpeter toàn cầu. Có cái đó

Daniel Nuriev

cám ơn vì đã giải thích. Trong trường hợp này tôi có một câu hỏi khác. có đúng là nếu một luồng chạy hơn 10 mili giây, Python VM sẽ chuyển sang luồng tiếp theo để không bị kẹt không?

Daniel Nuriev

cám ơn vì đã giải thích. Trong trường hợp này tôi có một câu hỏi khác. có đúng là nếu một luồng chạy hơn 10 mili giây, Python VM sẽ chuyển sang luồng tiếp theo để không bị kẹt không?

mattias

Từ những gì tôi có thể google nhanh chóng, bất kỳ chuỗi liên kết cpu nào (nghĩa là không đợi i/o) đang giải phóng gil (và yêu cầu gửi lại. -mua nó) cứ sau 100 tích tắc. Tôi không chắc dấu tích chính xác là gì nhưng tôi nghi ngờ đó là chu kỳ cpu, mà đúng hơn là một số vòng lặp thực thi trong chính trình thông dịch, tôi đoán vậy. -). Dù sao thì điều này đảm bảo tất cả các luồng đều có thời gian thực hiện, nhưng hình phạt quá cao nên việc cố gắng thực hiện nhiều luồng cùng một lúc sẽ tệ hơn nhiều so với việc chạy các tác vụ một cách tuần tự. Tôi đã tìm thấy trang trình bày này giải thích lịch trình cho tôi, vì vậy hãy lấy nó để làm khách mời. ). http. //www. dabeaz. com/python/Hiểu biếtGIL. pdf

mattias

Từ những gì tôi có thể google nhanh chóng, bất kỳ chuỗi liên kết cpu nào (nghĩa là không đợi i/o) đang giải phóng gil (và yêu cầu gửi lại. -mua nó) cứ sau 100 tích tắc. Tôi không chắc dấu tích chính xác là gì nhưng tôi nghi ngờ đó là chu kỳ cpu, mà đúng hơn là một số vòng lặp thực thi trong chính trình thông dịch, tôi đoán vậy. -). Dù sao thì điều này đảm bảo tất cả các luồng đều có thời gian thực hiện, nhưng hình phạt quá cao nên việc cố gắng thực hiện nhiều luồng cùng một lúc sẽ tệ hơn nhiều so với việc chạy các tác vụ một cách tuần tự. Tôi đã tìm thấy trang trình bày này giải thích lịch trình cho tôi, vì vậy hãy lấy nó để làm khách mời. ). http. //www. dabeaz. com/python/Hiểu biếtGIL. pdf

Sở thích

Tôi cố gắng tạo lại mã này để hiểu về đa luồng. Nhưng tôi đã gặp lỗi khi tôi chạy nó. tiêu đề = {'Ủy quyền'. 'ID khách hàng {}'. định dạng (client_id)} -> đầu ra. Tiêu đề yêu cầu không hợp lệ = {'Ủy quyền'. 'ID ứng dụng khách {{}}'. định dạng (client_id)} -> đầu ra. Quyền bị từ chối Tôi có cần tải hình ảnh lên tài khoản imgur của mình không?

Sở thích

Tôi cố gắng tạo lại mã này để hiểu về đa luồng. Nhưng tôi đã gặp lỗi khi tôi chạy nó. tiêu đề = {'Ủy quyền'. 'ID khách hàng {}'. định dạng (client_id)} -> đầu ra. Tiêu đề yêu cầu không hợp lệ = {'Ủy quyền'. 'ID ứng dụng khách {{}}'. định dạng (client_id)} -> đầu ra. Quyền bị từ chối Tôi có cần tải hình ảnh lên tài khoản imgur của mình không?

Kevin

Tôi đã lấy ví dụ luồng ban đầu của bạn và viết một số mã hoạt động rất tốt. Tuy nhiên, nhiệm vụ là nó phải chạy bên trong máy chủ web và mặc dù nó chạy tốt như nhau ở đó, nhưng có thể nói đó là "tích lũy luồng" vì python không thực sự thoát cho đến khi máy chủ web bị tắt. e. g. Tôi đang tạo ra tám luồng và mỗi khi điểm cuối được thực thi, nó sẽ sử dụng một bộ mới. Tôi biết điều này bởi vì tôi đang viết các tên luồng riêng lẻ (luồng. current_thread(). getName()) và tổng số vào tệp nhật ký. Điều này đúng bất kể tôi có đặt chúng là daemon hay không. Tôi không phải là bậc thầy về trăn. Bất kỳ đầu vào/đề xuất nào về cách tôi có thể liên tục sử dụng lại cùng một nhóm luồng (một khi được xác định trong lần thực thi ban đầu) hoặc cách khác là "xóa" các đối tượng luồng để chúng không tiếp tục tích lũy?

Kevin

Tôi đã lấy ví dụ luồng ban đầu của bạn và viết một số mã hoạt động rất tốt. Tuy nhiên, nhiệm vụ là nó phải chạy bên trong máy chủ web và mặc dù nó chạy tốt như nhau ở đó, nhưng có thể nói đó là "tích lũy luồng" vì python không thực sự thoát cho đến khi máy chủ web bị tắt. e. g. Tôi đang tạo ra tám luồng và mỗi khi điểm cuối được thực thi, nó sẽ sử dụng một bộ mới. Tôi biết điều này bởi vì tôi đang viết các tên luồng riêng lẻ (luồng. current_thread(). getName()) và tổng số vào tệp nhật ký. Điều này đúng bất kể tôi có đặt chúng là daemon hay không. Tôi không phải là bậc thầy về trăn. Bất kỳ đầu vào/đề xuất nào về cách tôi có thể liên tục sử dụng lại cùng một nhóm luồng (một khi được xác định trong lần thực thi ban đầu) hoặc cách khác là "xóa" các đối tượng luồng để chúng không tiếp tục tích lũy?

Marcus McCurdy

Này Kevin, thật khó để nói chính xác cách hành động tốt nhất là gì nếu không biết thêm một chút về những gì có thể gọi được trong chuỗi của bạn đang làm. Nếu chủ đề của bạn giống như lớp DownloadWorker của tôi trong ví dụ đó có thể không phải là cách tiếp cận tốt nhất cho trường hợp sử dụng của bạn. Các tài liệu về lớp chủ đề https. // tài liệu. con trăn. tổ chức/3. 6/thư viện/luồng. html#thread-object nói. "Khi hoạt động của chuỗi được bắt đầu, chuỗi được coi là 'còn sống'. Nó ngừng hoạt động khi phương thức run() của nó kết thúc - thông thường hoặc bằng cách đưa ra một ngoại lệ chưa được xử lý. Phương thức is_alive() kiểm tra xem thread còn sống hay không. " vì vậy nếu phương thức chạy của bạn trên lớp kế thừa từ Chủ đề kết thúc và thoát khỏi luồng sẽ không còn tồn tại. Bạn có thể muốn kiểm tra ví dụ cập nhật của tôi sử dụng https. // tài liệu. con trăn. org/3/library/concurrent. tương lai. html#threadpoolexecutor. Với trình thực thi, bạn chọn số lượng chủ đề tối đa tạo nên nhóm. Sau đó, bạn gửi nhiệm vụ cho người thực thi, người sẽ sử dụng một trong các luồng có sẵn trong nhóm hoặc khối cho đến khi có sẵn một luồng. Khi bạn đã tạo trình thực thi của mình, bạn gọi phương thức gửi trên trình thực thi để tác vụ của bạn chạy không đồng bộ trên một trong các luồng. Gửi trả về một tương lai mà sau đó bạn có thể sử dụng để nhận kết quả. Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể không cần sử dụng tương lai gửi trả lại. ThreadPoolExecutor nghe giống như những gì bạn đang tìm kiếm vì bạn nói rằng bạn muốn "sử dụng lại cùng một bộ chủ đề" Hy vọng rằng điều này sẽ hữu ích. Nếu không, vui lòng gửi email một ý chính với một ví dụ về mã. email của tôi là tên của tôi dấu chấm họ tại toptal dot com

Marcus McCurdy

Này Kevin, thật khó để nói chính xác cách hành động tốt nhất là gì nếu không biết thêm một chút về những gì có thể gọi được trong chuỗi của bạn đang làm. Nếu chủ đề của bạn giống như lớp DownloadWorker của tôi trong ví dụ đó có thể không phải là cách tiếp cận tốt nhất cho trường hợp sử dụng của bạn. Các tài liệu về lớp chủ đề https. // tài liệu. con trăn. tổ chức/3. 6/thư viện/luồng. html#thread-object nói. "Khi hoạt động của chuỗi được bắt đầu, chuỗi được coi là 'còn sống'. Nó ngừng hoạt động khi phương thức run() của nó kết thúc - thông thường hoặc bằng cách đưa ra một ngoại lệ chưa được xử lý. Phương thức is_alive() kiểm tra xem thread còn sống hay không. " vì vậy nếu phương thức chạy của bạn trên lớp kế thừa từ Chủ đề kết thúc và thoát khỏi luồng sẽ không còn tồn tại. Bạn có thể muốn kiểm tra ví dụ cập nhật của tôi sử dụng https. // tài liệu. con trăn. org/3/library/concurrent. tương lai. html#threadpoolexecutor. Với trình thực thi, bạn chọn số lượng chủ đề tối đa tạo nên nhóm. Sau đó, bạn gửi nhiệm vụ cho người thực thi, người sẽ sử dụng một trong các luồng có sẵn trong nhóm hoặc khối cho đến khi có sẵn một luồng. Khi bạn đã tạo trình thực thi của mình, bạn gọi phương thức gửi trên trình thực thi để tác vụ của bạn chạy không đồng bộ trên một trong các luồng. Gửi trả về một tương lai mà sau đó bạn có thể sử dụng để nhận kết quả. Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể không cần sử dụng tương lai gửi trả lại. ThreadPoolExecutor nghe giống như những gì bạn đang tìm kiếm vì bạn nói rằng bạn muốn "sử dụng lại cùng một bộ chủ đề" Hy vọng rằng điều này sẽ hữu ích. Nếu không, vui lòng gửi email một ý chính với một ví dụ về mã. email của tôi là tên của tôi dấu chấm họ tại toptal dot com

ihadanny

GHI CHÚ. đối với bất kỳ ai đang cố chạy mã này ngay bây giờ (2018), api imgur đã thay đổi, nếu bạn cố truy cập https. //api. imgur. com/3/gallery/ bạn sẽ gặp lỗi `Yêu cầu không hợp lệ`. thay vào đó hãy sử dụng https. //api. imgur. com/3/gallery/ngẫu nhiên/ngẫu nhiên/

ihadanny

GHI CHÚ. đối với bất kỳ ai đang cố chạy mã này ngay bây giờ (2018), api imgur đã thay đổi, nếu bạn cố truy cập https. //api. imgur. com/3/gallery/ bạn sẽ gặp lỗi `Yêu cầu không hợp lệ`. thay vào đó hãy sử dụng https. //api. imgur. com/3/gallery/ngẫu nhiên/ngẫu nhiên/

ihadanny

API imgur đã thay đổi, hãy sử dụng https. //api. imgur. com/3/gallery/random/random/ thay vào đó

ihadanny

API imgur đã thay đổi, hãy sử dụng https. //api. imgur. com/3/gallery/random/random/ thay vào đó

Marcus McCurdy

Xin lỗi vì điều đó. Có vẻ như chúng tôi đã quên cập nhật đoạn mã đầu tiên của bài đăng trên blog. Mã thực sự chính xác trong repo Github https. //github. com/volker48/python-concurrency/blob/master/download. py#L19. Chúng tôi sẽ cập nhật đoạn trích trong bài đăng trên blog. Cảm ơn bạn đã chỉ ra vấn đề

Marcus McCurdy

Xin lỗi vì điều đó. Có vẻ như chúng tôi đã quên cập nhật đoạn mã đầu tiên của bài đăng trên blog. Mã thực sự chính xác trong repo Github https. //github. com/volker48/python-concurrency/blob/master/download. py#L19. Chúng tôi sẽ cập nhật đoạn trích trong bài đăng trên blog. Cảm ơn bạn đã chỉ ra vấn đề

Kevin Bloch

Bài viết đã được cập nhật

Kevin Bloch

Bài viết đã được cập nhật

André Zunino

Tôi đang chạy Python 3. 6. 5 và phải thay đổi lệnh gọi phương thức 'readall' trên các đối tượng HTTPResponse được trả về từ urllib. phương thức urlopen của yêu cầu (trong phần tải xuống. py). Tôi không biết liệu chúng có bị xóa khỏi API HTTPResponse trong các phiên bản gần đây hay không nhưng tôi thấy có một phương pháp 'đọc' có thể được sử dụng

André Zunino

Tôi đang chạy Python 3. 6. 5 và phải thay đổi lệnh gọi phương thức 'readall' trên các đối tượng HTTPResponse được trả về từ urllib. phương thức urlopen của yêu cầu (trong phần tải xuống. py). Tôi không biết liệu chúng có bị xóa khỏi API HTTPResponse trong các phiên bản gần đây hay không nhưng tôi thấy có một phương pháp 'đọc' có thể được sử dụng

Pablo Messina

Nếu tôi muốn sử dụng nhiều lõi nhưng các tác vụ cần chia sẻ cùng một dữ liệu chỉ đọc thì sao? . 1) một cơ sở dữ liệu về các giao dịch, tôi. e. một danh sách các Sự kiện mua hàng được sắp xếp (trong đó Sự kiện mua hàng là một Lớp chứa dữ liệu như dấu thời gian, ID của mặt hàng đã mua, ID của khách hàng, v.v. ) và 2) một số ma trận đối tượng cục bộ lớn có kích thước N x F (N = số mục, F = số đối tượng) và có thể 3) một số từ điển ánh xạ ID mục tới siêu dữ liệu bổ sung. Để tăng tốc quy trình, lý tưởng nhất là chạy nhiều thử nghiệm đồng thời nhưng chia sẻ dữ liệu chỉ đọc, vì sẽ không khả thi để sao chép dữ liệu cho mỗi quy trình (sẽ rất tốn thời gian và không phù hợp với . Bạn có biết làm thế nào một cái gì đó như thế này có thể được thực hiện? . Tôi đoán Đa xử lý nên là con đường để đi, nhưng sau đó tôi phải đối mặt với vấn đề chia sẻ nhiều dữ liệu chỉ đọc (danh sách các đối tượng lớp, mảng có nhiều mảng, từ điển, v.v. ). CẬP NHẬT. Ngoài ra, bất kể giải pháp nào bạn đề xuất, liệu giải pháp đó có còn hoạt động không nếu tôi đang chạy các thử nghiệm này từ Máy tính xách tay Jupyter IPython tương tác trên Windows 10? . Tôi vừa đăng câu hỏi này rất giống nhau trên Stackoverflow. https. // stackoverflow. com/câu hỏi/51690339/run-concurrent-tasks-via-pool-of-child-processes-sharing-complex-data-memory-sh

Pablo Messina

Nếu tôi muốn sử dụng nhiều lõi nhưng các tác vụ cần chia sẻ cùng một dữ liệu chỉ đọc thì sao? . 1) một cơ sở dữ liệu về các giao dịch, tôi. e. một danh sách các Sự kiện mua hàng được sắp xếp (trong đó Sự kiện mua hàng là một Lớp chứa dữ liệu như dấu thời gian, ID của mặt hàng đã mua, ID của khách hàng, v.v. ) và 2) một số ma trận đối tượng cục bộ lớn có kích thước N x F (N = số mục, F = số đối tượng) và có thể 3) một số từ điển ánh xạ ID mục tới siêu dữ liệu bổ sung. Để tăng tốc quy trình, lý tưởng nhất là chạy nhiều thử nghiệm đồng thời nhưng chia sẻ dữ liệu chỉ đọc, vì sẽ không khả thi để sao chép dữ liệu cho mỗi quy trình (sẽ rất tốn thời gian và không phù hợp với . Bạn có biết làm thế nào một cái gì đó như thế này có thể được thực hiện? . Tôi đoán Đa xử lý nên là con đường để đi, nhưng sau đó tôi phải đối mặt với vấn đề chia sẻ nhiều dữ liệu chỉ đọc (danh sách các đối tượng lớp, mảng có nhiều mảng, từ điển, v.v. ). CẬP NHẬT. Ngoài ra, bất kể giải pháp nào bạn đề xuất, liệu giải pháp đó có còn hoạt động không nếu tôi đang chạy các thử nghiệm này từ Máy tính xách tay Jupyter IPython tương tác trên Windows 10? . Tôi vừa đăng câu hỏi này rất giống nhau trên Stackoverflow. https. // stackoverflow. com/câu hỏi/51690339/run-concurrent-tasks-via-pool-of-child-processes-sharing-complex-data-memory-sh

Kevin Bloch

Xin chào Andre--cảm ơn bạn rất nhiều vì đã chỉ ra điều này. Phần gốc của bài viết hiện đã được cập nhật để phù hợp với các phiên bản hiện tại trên GitHub, bao gồm các bản sửa lỗi bạn đã đề cập

Kevin Bloch

Xin chào Andre--cảm ơn bạn rất nhiều vì đã chỉ ra điều này. Phần gốc của bài viết hiện đã được cập nhật để phù hợp với các phiên bản hiện tại trên GitHub, bao gồm các bản sửa lỗi bạn đã đề cập

andrei deuşteanu

Một hạn chế của thư viện đa xử lý mà tôi đã gặp là nó không thể hoạt động với các hàm lambda vì các hàm được chọn theo tên và do đó các hàm lambda là ẩn danh, chúng không được chọn. Tôi đã thử ngâm chúng thủ công với thì là nhưng không thành công. Nhưng sau đó tôi bắt gặp đa xử lý - https. //github. thư viện com/uqfoundation/multiprocess giúp mọi thứ thực sự dễ dàng chạy song song. Nó thực sự là một phần của khuôn khổ lớn hơn cho các mầm bệnh điện toán không đồng nhất - https. //github. com/uqfoundation/pathos. Bạn nên kiểm tra xem nó ra. Tôi không làm việc trên thư viện, nhưng tôi đã sử dụng nó một vài lần và nó rất dễ sử dụng, đó là lý do tại sao tôi quảng cáo nó

andrei deuşteanu

Một hạn chế của thư viện đa xử lý mà tôi đã gặp là nó không thể hoạt động với các hàm lambda vì các hàm được chọn theo tên và do đó các hàm lambda là ẩn danh, chúng không được chọn. Tôi đã thử ngâm chúng thủ công với thì là nhưng không thành công. Nhưng sau đó tôi bắt gặp đa xử lý - https. //github. thư viện com/uqfoundation/multiprocess giúp mọi thứ thực sự dễ dàng chạy song song. Nó thực sự là một phần của khuôn khổ lớn hơn cho các mầm bệnh điện toán không đồng nhất - https. //github. com/uqfoundation/pathos. Bạn nên kiểm tra xem nó ra. Tôi không làm việc trên thư viện, nhưng tôi đã sử dụng nó một vài lần và nó rất dễ sử dụng, đó là lý do tại sao tôi quảng cáo nó

Tắm Pawan

Tôi không thể hiểu làm thế nào 8 luồng được tạo trong ví dụ đầu tiên kết thúc quá trình thực thi và thoát khỏi phương thức run()?

Tắm Pawan

Tôi không thể hiểu làm thế nào 8 luồng được tạo trong ví dụ đầu tiên kết thúc quá trình thực thi và thoát khỏi phương thức run()?

Tắm Pawan

Và cảm ơn vì bài viết rõ ràng, súc tích và toàn diện

Tắm Pawan

Và cảm ơn vì bài viết rõ ràng, súc tích và toàn diện

Antony Raj

Bạn có thể thấy cách chúng tôi có thể sử dụng đồng thời. tương lai đây https. //Blog. franxi. tech/global-interpreter-lock-gil-and-concurrent-execution-in-python-70f17f09e892

Antony Raj

Bạn có thể thấy cách chúng tôi có thể sử dụng đồng thời. tương lai đây https. //Blog. franxi. tech/global-interpreter-lock-gil-and-concurrent-execution-in-python-70f17f09e892

jie yang

Vì 8 luồng là daemon nên khi các task trong queue làm hết thì queue. tham gia () bỏ chặn, luồng chính kết thúc và 8 luồng daemon biến mất

jie yang

Vì 8 luồng là daemon nên khi các task trong queue làm hết thì queue. tham gia () bỏ chặn, luồng chính kết thúc và 8 luồng daemon biến mất

Erdem Öntaş

Xin chào Marcus tôi có một câu hỏi cho bạn. Tôi có một chương trình chạy trên Raspberry Pi và có kèm theo đầu đọc thẻ. Tôi đang thu thập các Thẻ RF và gửi chúng đến máy chủ và việc đợi phản hồi của máy chủ đôi khi có thể mất tới 5 giây. Nó khiến chương trình của tôi chờ trong 5 giây này để trình đọc không hoạt động trong 5 tác phẩm này. Ngoài ra còn có một chương trình GUI. Tôi không thể tìm ra thư viện nào tôi nên sử dụng cho nhu cầu của mình. tôi nảy ra ý tưởng này. Trình đọc phải hoạt động như luồng chính và thêm THẺ RF vào hàng đợi và một luồng khác (hoặc quá trình tôi không chắc nên sử dụng cái nào) nên kiểm tra hàng đợi và gửi và chờ phản hồi trong khi trình đọc tiếp tục đọc. Bạn có gợi ý nào không?

Rêu Rêu

Xin chào Marcus - khám phá tuyệt vời về các tùy chọn khác nhau ngoài kia. Tôi đã tự hỏi lời khuyên của bạn sẽ là gì cho kịch bản này. Tôi có một ứng dụng python chạy trên AWS EC2. Nó được gọi định kỳ bởi một máy chủ web nodeJS để thực hiện một số xử lý hình ảnh chuyên sâu của CPU trên một tập hợp các hình ảnh. Tổng thời gian xử lý có thể là 20-30 giây cho khoảng 10-15 hình ảnh (trăn tuần tự tiêu chuẩn một luồng/xử lý). Thay vào đó, để thực hiện điều này "ngay lập tức", điều tôi dự định làm là chuyển từng hình ảnh đó thành một hàm AWS lambda để tất cả chúng có thể chạy song song - một phiên bản lambda được gọi trên mỗi hình ảnh và do đó, tổng thời gian đồng hồ . Gọi các hàm lambda AWS - khi bạn muốn nhận lại phản hồi - có nghĩa là gọi chúng một cách đồng bộ. Vì vậy, để gọi tất cả chúng song song có nghĩa là hàm python cha phải tạo đồng thời. Để làm điều đó, tôi đang xem xét một trong hai a) đồng thời. tương lai, hoặc b) asyncio. Tôi đã tự hỏi suy nghĩ của bạn về những gì có thể là tốt nhất? . Richard

gia đình

Này R, bạn đã bao giờ tìm ra điều này chưa? . Tôi tin rằng tôi sắp giải quyết được vấn đề, nhưng tôi rất muốn biết bạn đã làm gì, nếu có thể. Trân trọng, J

Raphael

Tôi tin rằng, các tác vụ đa luồng của Python sử dụng cùng một lõi CPU. Đối với đa lõi, gói phải là đa xử lý và không phân luồng

Việc sử dụng mô-đun luồng trong Python là gì?

Mô-đun phân luồng mới hơn đi kèm với Python 2. 4 cung cấp hỗ trợ cấp cao, mạnh mẽ hơn nhiều cho luồng so với mô-đun luồng đã thảo luận trong phần trước. luồng. activeCount() - Trả về số đối tượng luồng đang hoạt động. luồng.

Các loại chủ đề trong Python là gì?

Có hai loại chủ đề riêng biệt. đó là. Chủ đề cấp người dùng. Đây là những thứ chúng ta có thể tích cực chơi với mã của mình, v.v. Luồng cấp hạt nhân. Đây là những luồng cấp rất thấp hoạt động thay mặt cho hệ điều hành .

Mô-đun nào được sử dụng để đa luồng trong Python?

Python hỗ trợ 2 mô-đun cho đa luồng. mô-đun __thread. Nó cung cấp triển khai cấp thấp cho luồng và đã lỗi thời. mô-đun luồng. Nó cung cấp triển khai cấp cao cho đa luồng và là tiêu chuẩn hiện hành

Sự khác biệt giữa Asyncio và phân luồng Python là gì?

Asyncio so với luồng. Async chạy mỗi lần một khối mã trong khi mỗi lần chỉ phân luồng một dòng mã . Với async, chúng tôi kiểm soát tốt hơn khi thực thi được cấp cho khối mã khác nhưng chúng tôi phải tự giải phóng thực thi.