Lộ trình học đồng thời Python

"Trong hơn một thập kỷ, các nhà tiên tri đã lên tiếng tranh luận rằng tổ chức của một máy tính duy nhất đã đạt đến giới hạn của nó và những tiến bộ thực sự quan trọng chỉ có thể được thực hiện bằng cách kết nối nhiều máy tính với nhau. "

-Gene Amdahl

Tận dụngthehầu hết phần mềm của bạn là điều mà tất cả các nhà phát triển đều phấn đấu và đồng thời, và . Thông qua việc áp dụng cẩn thận các khái niệm đồng thời vào các ứng dụng đơn luồng trước đây của chúng tôi, chúng tôi có thể bắt đầu nhận ra toàn bộ sức mạnh của phần cứng cơ bản và cố gắng giải quyết các vấn đề không thể giải quyết được trong những ngày qua.

Với đồng thời, chúng tôi có thể cải thiện hiệu suất nhận thức của các ứng dụng của mình bằng cách xử lý đồng thời các yêu cầu và cập nhật giao diện người dùng thay vì chỉ bị treo cho đến khi hoàn tất tác vụ phụ trợ. Đã qua rồi cái thời của các chương trình không phản hồi không cho bạn biết liệu chúng đã bị lỗi hay vẫn đang hoạt động âm thầm

Mặc dù vậy, sự cải thiện về hiệu suất của các ứng dụng của chúng tôi phải trả giá đắt. Bằng cách chọn triển khai các hệ thống theo kiểu đồng thời, chúng tôi thường thấy độ phức tạp tổng thể của mã tăng lên và nguy cơ lỗi xuất hiện trong mã mới này tăng cao. Để triển khai thành công các hệ thống đồng thời, trước tiên chúng ta phải hiểu một số nguyên tắc và khái niệm đồng thời chính ở cấp độ sâu hơn để đảm bảo rằng các ứng dụng của chúng ta an toàn trước các mối đe dọa cố hữu mới này

Trong chương này, tôi sẽ đề cập đến một số chủ đề cơ bản mà mọi lập trình viên cần biết trước khi tiếp tục phát triển các hệ thống phần mềm đồng thời. Điều này bao gồm những điều sau đây

  • Sơ lược về lịch sử đồng thời
  • Chủ đề và cách đa luồng hoạt động
  • Quy trình và đa xử lý
  • Khái niệm cơ bản về lập trình dựa trên sự kiện, phản ứng và dựa trên GPU
  • Một vài ví dụ để chứng minh sức mạnh của đồng thời trong các chương trình đơn giản
  • T những hạn chế của Python khi lập trình các hệ thống đồng thời

 

Lịch sử đồng thời


Tính đồng thời thực sự bắt nguồn từ công việc ban đầu trên đường sắt và điện báo, đó là lý do tại sao những cái tên như semaphore hiện đang được sử dụng. Về cơ bản, cần phải xử lý nhiều đoàn tàu trên cùng một hệ thống đường sắt theo cách mà mọi đoàn tàu sẽ đến đích một cách an toàn mà không gây thương vong.

Chỉ trong những năm 1960, giới học thuật mới bắt đầu up quan tâm đến tính toán đồng thời và đó là Edsger W. Dijkstra, người được cho là đã xuất bản bài báo đầu tiên trong lĩnh vực này, trong đó ông đã xác định và giải quyết vấn đề loại trừ lẫn nhau. Dijkstra sau đó tiếp tục xác định các khái niệm đồng thời cơ bản, chẳng hạn như semaphores, loại trừ lẫn nhau và bế tắc cũng như Thuật toán đường đi ngắn nhất nổi tiếng của Dijkstra.

Đồng thời, giống như hầu hết các lĩnh vực trong khoa học máy tính, vẫn là một lĩnh vực cực kỳ non trẻ khi so sánh với các lĩnh vực nghiên cứu khác như toán học, và bạn nên ghi nhớ điều này. Vẫn còn tiềm năng to lớn cho sự thay đổi trong lĩnh vực này và nó vẫn là một lĩnh vực thú vị cho tất cả mọi người--các học giả, nhà thiết kế ngôn ngữ và nhà phát triển--như nhau

Việc giới thiệu nguyên mẫu đồng thời cấp cao và hỗ trợ ngôn ngữ bản địa tốt hơn đã thực sự cải thiện cách thức mà chúng tôi, với tư cách là kiến ​​trúc sư phần mềm, triển khai các giải pháp đồng thời. Trong nhiều năm, điều này cực kỳ khó thực hiện, nhưng với sự ra đời của các API đồng thời mới cũng như các khung và ngôn ngữ hoàn thiện, nó bắt đầu trở nên dễ dàng hơn rất nhiều đối với chúng tôi với tư cách là nhà phát triển

Các nhà thiết kế ngôn ngữ phải đối mặt với một thách thức khá lớn khi cố gắng triển khai đồng thời không chỉ an toàn mà còn hiệu quả và dễ viết cho người dùng ngôn ngữ đó. Các ngôn ngữ lập trình như Golang của Google, Rust và thậm chí cả Python đã có những bước tiến lớn trong lĩnh vực này và điều này giúp việc khai thác toàn bộ tiềm năng từ các máy mà chương trình của bạn chạy trên đó trở nên dễ dàng hơn rất nhiều.

 

Chủ đề và đa luồng


Trong phần này của cuốn sách, chúng ta sẽ tìm hiểu sơ qua về chuỗi là gì, cũng như cách thức chúng ta có thể .

một chủ đề là gì?

Một luồng có thể được định nghĩa là một luồng các lệnh có thứ tự mà các hệ điều hành có thể lên lịch để chạy như vậy. Thông thường, các luồng này nằm trong các quy trình và bao gồm bộ đếm chương trình, ngăn xếp và tập hợp các thanh ghi cũng như mã định danh. Các luồng này là đơn vị thực thi nhỏ nhất mà bộ xử lý có thể phân bổ thời gian.

Các luồng có thể tương tác với các tài nguyên được chia sẻ và có thể giao tiếp giữa nhiều luồng. Họ cũng có thể chia sẻ bộ nhớ, đọc và ghi các địa chỉ bộ nhớ khác nhau, nhưng trong đó có một vấn đề. Khi hai luồng bắt đầu chia sẻ bộ nhớ và bạn không có cách nào để đảm bảo thứ tự thực thi của luồng, bạn có thể bắt đầu thấy các sự cố hoặc lỗi nhỏ cung cấp cho bạn các giá trị sai hoặc làm hệ thống của bạn bị sập hoàn toàn. Những vấn đề này chủ yếu là do điều kiện chủng tộc gây ra mà chúng ta sẽ đi sâu hơn trong Chương 4, Đồng bộ hóa giữa các luồng.

Hình dưới đây cho thấy cách nhiều luồng có thể tồn tại trên nhiều CPU khác nhau

Lộ trình học đồng thời Python

Các loại chủ đề

Trong một hệ điều hành điển hình, chúng ta thường có hai loại luồng riêng biệt

  • Chủ đề cấp người dùng. Các luồng mà chúng ta có thể chủ động tạo, chạy và hủy cho tất cả các tác vụ khác nhau của mình của mình của mình của mình của mình của mình của mình của mình của mình của mình của mình
  • Chủ đề cấp hạt nhân. Các luồng cấp rất thấp hoạt động thay mặt cho hệ điều hành

Python hoạt động ở cấp độ người dùng và do đó, mọi thứ chúng tôi trình bày trong cuốn sách này sẽ chủ yếu tập trung vào các chuỗi cấp độ người dùng này .

Đa luồng là gì?

Khi mọi người nói về bộ xử lý đa luồng, họ thường đề cập đến đến một bộ xử lý có thể chạy nhiều luồng đồng thời mà họ có thể thực hiện . Bối cảnh chuyển đổi này diễn ra trong một khoảng thời gian ngắn đến mức chúng ta có thể cho rằng có nhiều luồng đang chạy song song trong khi thực tế thì không phải như vậy .

Khi cố gắng hiểu về đa luồng, tốt nhất bạn nên nghĩ về một chương trình đa luồng như một văn phòng. Trong một chương trình đơn luồng, sẽ chỉ có một người làm việc trong văn phòng này mọi lúc, xử lý tất cả các công việc một cách tuần tự. Điều này sẽ trở thành một vấn đề nếu chúng ta xem xét điều gì sẽ xảy ra khi người lao động đơn độc này sa lầy vào công việc giấy tờ hành chính và không thể chuyển sang công việc khác. Họ sẽ không thể đối phó và sẽ không thể đối phó với doanh số bán hàng mới sắp tới, do đó làm tiêu tốn tiền kinh doanh ẩn dụ của chúng tôi

Với đa luồng, nhân viên đơn độc của chúng tôi trở thành một người đa nhiệm xuất sắc và có thể làm việc trên nhiều thứ vào những thời điểm khác nhau. Họ có thể đạt được tiến bộ trong một số thủ tục giấy tờ và sau đó chuyển ngữ cảnh sang một nhiệm vụ mới khi có điều gì đó bắt đầu ngăn cản họ thực hiện thêm công việc trên các thủ tục giấy tờ nói trên. Bằng cách có thể chuyển ngữ cảnh khi có thứ gì đó chặn họ, họ có thể làm được nhiều việc hơn trong một khoảng thời gian ngắn hơn và do đó giúp doanh nghiệp của chúng tôi kiếm được nhiều tiền hơn

Trong ví dụ này, điều quan trọng cần lưu ý là chúng tôi vẫn chỉ giới hạn ở một công nhân hoặc lõi xử lý. Nếu chúng tôi muốn thử và cải thiện khối lượng công việc mà doanh nghiệp có thể thực hiện và hoàn thành công việc song song, thì chúng tôi sẽ phải thuê những công nhân hoặc quy trình khác như chúng tôi gọi họ trong Python

Hãy xem một vài ưu điểm của luồng

  • Nhiều luồng là tuyệt vời để tăng tốc chặn các chương trình ràng buộc I/O
  • Chúng nhẹ về dung lượng bộ nhớ khi so sánh với các quy trình
  • Chủ đề chia sẻ tài nguyên và do đó giao tiếp giữa chúng dễ dàng hơn

Có một số nhược điểm quá, đó là như sau

  • Các luồng CPython bị cản trở bởi các giới hạn của khóa trình thông dịch chung ( GIL), about which we'll go into more depth in the next chapter.
  • Mặc dù giao tiếp giữa các luồng có thể dễ dàng hơn, nhưng bạn phải hết sức cẩn thận để không triển khai mã tuân theo điều kiện
  • Việc chuyển ngữ cảnh giữa nhiều luồng rất tốn kém về mặt tính toán. Bằng cách thêm nhiều luồng, bạn có thể thấy hiệu suất tổng thể của chương trình bị suy giảm

 

quy trình


Các quy trình về bản chất rất giống nhau với các luồng--chúng cho phép chúng tôi thực hiện hầu hết mọi thứ mà một luồng có thể làm--nhưng quy trình . Nếu chúng ta mở rộng phép loại suy văn phòng của mình hơn nữa, về cơ bản, điều này có nghĩa là nếu chúng ta có CPU bốn lõi, thì chúng ta có thể thuê hai thành viên nhóm bán hàng chuyên dụng và hai công nhân, và cả bốn người trong số họ sẽ có thể thực hiện công việc song song. Các quy trình cũng có khả năng xử lý nhiều việc cùng một lúc giống như nhân viên văn phòng đa luồng của chúng tôi.

Các quy trình này chứa một luồng chính chính, nhưng có thể sinh ra nhiều luồng phụ, mỗi luồng chứa một bộ thanh ghi và ngăn xếp riêng. Chúng có thể trở thành đa luồng nếu bạn muốn. Tất cả các quy trình cung cấp mọi tài nguyên mà máy tính cần để thực thi chương trình

Trong hình ảnh sau đây, bạn sẽ thấy hai sơ đồ cạnh nhau; . Bạn sẽ nhận thấy rằng quy trình bên trái chỉ chứa một luồng, còn được gọi là luồng chính. Quá trình bên phải chứa nhiều luồng, mỗi luồng có bộ thanh ghi và ngăn xếp riêng

Lộ trình học đồng thời Python

Với các quy trình, chúng tôi có thể cải thiện tốc độ của các chương trình trong các tình huống cụ thể trong đó các chương trình của chúng tôi bị ràng buộc bởi CPU và yêu cầu nhiều mã lực CPU hơn. Tuy nhiên, bằng cách sinh ra nhiều quy trình, chúng tôi phải đối mặt với những thách thức mới liên quan đến giao tiếp giữa các quy trình và đảm bảo rằng chúng tôi không cản trở hiệu suất do chi tiêu quá nhiều . inter-process communication (IPC).

Thuộc tính của các quy trình

các quy trình UNIX được tạo bởi hệ điều hành và thường chứa các phần sau.

  • ID quy trình, ID nhóm quy trình, ID người dùng và ID nhóm
  • Môi trường
  • Thư mục làm việc
  • hướng dẫn chương trình
  • đăng ký
  • Cây rơm
  • đống
  • bộ mô tả tệp
  • hành động tín hiệu
  • thư viện dùng chung
  • Các công cụ giao tiếp giữa các quá trình (chẳng hạn như hàng đợi tin nhắn, đường ống, semaphores hoặc bộ nhớ dùng chung)

Ưu điểm của quy trình được liệt kê như sau.

  • Các quy trình có thể sử dụng tốt hơn bộ xử lý đa lõi
  • Chúng tốt hơn nhiều luồng trong việc xử lý các tác vụ sử dụng nhiều CPU
  • Chúng ta có thể vượt qua những hạn chế của GIL bằng cách tạo ra nhiều quy trình
  • Các quy trình gặp sự cố sẽ không giết chết toàn bộ chương trình của chúng tôi

Dưới đây là những nhược điểm của quy trình

  • Không có tài nguyên được chia sẻ giữa các quy trình--chúng tôi phải triển khai một số dạng IPC
  • Chúng đòi hỏi nhiều bộ nhớ hơn

 

đa xử lý


Trong Python, chúng tôi có thể chọn chạy mã của mình bằng cách sử dụng nhiều luồng hoặc nhiều quy trình nếu chúng tôi muốn thử và cải thiện hiệu suất hơn . Chúng ta có thể sử dụng phương pháp đa luồng và bị giới hạn ở khả năng xử lý của một lõi CPU hoặc ngược lại, chúng ta có thể sử dụng phương pháp đa xử lý và sử dụng toàn bộ số lõi CPU có sẵn trên máy của mình. Trong các máy tính hiện đại ngày nay, chúng ta có xu hướng có nhiều CPU và lõi, do đó, việc giới hạn bản thân chỉ sử dụng một lõi, khiến phần còn lại của máy không hoạt động một cách hiệu quả. Mục tiêu của chúng tôi là cố gắng khai thác toàn bộ tiềm năng từ phần cứng của mình và đảm bảo rằng chúng tôi nhận được giá trị đồng tiền bỏ ra tốt nhất cũng như giải quyết vấn đề của mình nhanh hơn bất kỳ ai khác.

Lộ trình học đồng thời Python

Với mô-đun đa xử lý của Python, chúng tôi có thể sử dụng hiệu quả toàn bộ số lõi và CPU, điều này có thể giúp chúng tôi đạt được hiệu suất cao hơn khi gặp sự cố giới hạn CPU. Hình trước cho thấy một ví dụ về cách một lõi CPU bắt đầu ủy thác nhiệm vụ cho các lõi khác

Trong tất cả các phiên bản Python nhỏ hơn hoặc bằng 2. 6, chúng ta có thể đạt được số lõi CPU có sẵn cho mình bằng cách sử dụng đoạn mã sau

# First we import the multiprocessing module
import multiprocessing 
# then we call multiprocessing.cpu_count() which 
# returns an integer value of how many available CPUs we have 
multiprocessing.cpu_count()

Không chỉ đa xử lý cho phép chúng tôi sử dụng máy của mình nhiều hơn mà còn tránh được những hạn chế mà Khóa phiên dịch toàn cầu đặt ra cho chúng tôi .

Một nhược điểm tiềm ẩn của nhiều quy trình là chúng ta vốn không có trạng thái chia sẻ và thiếu giao tiếp. Do đó, chúng tôi phải chuyển nó qua một số dạng IPC và hiệu suất có thể bị ảnh hưởng. Tuy nhiên, việc thiếu trạng thái chia sẻ này có thể giúp chúng làm việc dễ dàng hơn vì bạn không phải đấu tranh chống lại các điều kiện chủng tộc tiềm ẩn trong mã của mình

Lập trình hướng sự kiện

Lập trình hướng sự kiện là một phần quan trọng của cuộc sống của chúng ta--chúng ta thấy các ví dụ của< . Các thiết bị này chạy hoàn toàn theo cách hướng sự kiện; . it every day when we open up our phone, or work on our computer. These devices run purely in an event-driven way; for example, when you click on an icon on your desktop, the operating system registers this as an event, and then performs the necessary action tied to that specific style of event.

Mọi tương tác chúng ta thực hiện có thể được mô tả như một sự kiện hoặc một chuỗi sự kiện và những sự kiện này thường kích hoạt các cuộc gọi lại. Nếu bạn đã từng có bất kỳ kinh nghiệm nào với JavaScript, thì bạn sẽ phần nào quen thuộc với khái niệm gọi lại này và mẫu thiết kế gọi lại. Trong JavaScript, trường hợp sử dụng chủ yếu cho các cuộc gọi lại là khi bạn thực hiện các yêu cầu HTTP RESTful và muốn có thể thực hiện một hành động khi bạn biết rằng hành động này đã hoàn tất thành công và chúng tôi đã nhận được phản hồi HTTP của mình

Lộ trình học đồng thời Python

Nếu chúng ta nhìn vào hình ảnh trước đó, nó sẽ cho chúng ta thấy một ví dụ về cách các chương trình hướng sự kiện xử lý các sự kiện. Chúng tôi có Trình phát sự kiện ở phía bên trái; . Events, which are picked up by our program's Event Loop, and, should they match a predefined Event Handler, that handler is then fired to deal with the said event.

Gọi lại thường được sử dụng trong các tình huống trong đó một hành động không đồng bộ. Ví dụ: giả sử bạn đã nộp đơn xin việc tại Google, bạn sẽ cung cấp cho họ địa chỉ email và sau đó họ sẽ liên hệ với bạn khi họ quyết định. Về cơ bản, điều này giống như đăng ký gọi lại ngoại trừ việc thay vì yêu cầu họ gửi email cho bạn, bạn sẽ thực thi một đoạn mã tùy ý bất cứ khi nào gọi lại

Con rùa

Turtle là một mô-đun đồ họa đã được viết bằng Python và là một điểm khởi đầu đáng kinh ngạc . Nó xử lý tất cả sự phức tạp đi kèm với lập trình đồ họa và cho phép họ tập trung hoàn toàn vào việc học những điều cơ bản nhất trong khi vẫn khiến họ hứng thú. getting kids interested in programming. It handles all the complexities that come with graphics programming, and lets them focus purely on learning the very basics whilst keeping them interested.

Đây cũng là một công cụ rất tốt để sử dụng để để trình diễn các chương trình hướng sự kiện. Nó có tính năng xử lý sự kiện và trình lắng nghe, đó là tất cả những gì chúng ta cần.

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()

Phá vỡ nó

Trong dòng đầu tiên của mẫu mã trước này, chúng tôi nhập mô-đun đồ họa rùa . Sau đó, chúng tôi tiếp tục thiết lập cửa sổ rùa cơ bản với tiêu đề Xử lý sự kiện 101 và màu nền là xanh lam nhạt.

Sau khi thiết lập xong ban đầu, chúng ta sẽ tiếp tục xác định ba trình xử lý sự kiện riêng biệt

  • moveForward. Đây là khi chúng tôi muốn di chuyển nhân vật của mình về phía trước 50 đơn vị
  • moveLeft/moveRight . Cái này dùng khi chúng ta muốn xoay nhân vật của mình theo một hướng 30 độ

Lộ trình học đồng thời Python

Khi chúng tôi đã xác định ba trình xử lý riêng biệt của mình, chúng tôi sẽ tiếp tục ánh xạ các trình xử lý sự kiện này tới các lần nhấn phím lên, trái và phải bằng cách sử dụng phương thức

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
0

Bây giờ chúng tôi đã thiết lập trình xử lý của mình, sau đó chúng tôi yêu cầu họ bắt đầu lắng nghe. Nếu bất kỳ phím nào được nhấn sau khi chương trình của chúng tôi bắt đầu nghe, thì chúng tôi sẽ kích hoạt chức năng xử lý sự kiện của nó. Cuối cùng, khi bạn chạy mã trước đó, bạn sẽ thấy một cửa sổ xuất hiện với một mũi tên ở giữa, bạn có thể di chuyển cửa sổ này bằng các phím mũi tên của mình

 

lập trình phản ứng


Lập trình phản ứng rất giống với lập trình hướng sự kiện, nhưng thay vì xoay quanh các sự kiện, nó tập trung vào dữ liệu. Cụ thể hơn, nó xử lý các luồng dữ liệu và phản ứng với các thay đổi dữ liệu cụ thể.

ReacX - RxPy

RxPy tương đương với Python của khung ReactiveX rất phổ biến . Nếu bạn đã từng thực hiện bất kỳ chương trình nào trong Angular 2 và các phiên bản tiếp theo, thì bạn sẽ sử dụng chương trình này khi tương tác với các dịch vụ HTTP. Khung này là sự kết hợp của mẫu quan sát, mẫu iterator và lập trình chức năng. Về cơ bản, chúng tôi đăng ký các luồng dữ liệu đến khác nhau, sau đó tạo các trình quan sát lắng nghe các sự kiện cụ thể đang được kích hoạt. Khi các trình quan sát này được kích hoạt, chúng sẽ chạy mã tương ứng với những gì vừa xảy ra.

Chúng tôi sẽ lấy một trung tâm dữ liệu làm ví dụ điển hình về cách lập trình phản ứng có thể được sử dụng. Hãy tưởng tượng trung tâm dữ liệu này có hàng nghìn giá đỡ máy chủ, tất cả đều liên tục tính toán hàng triệu phép tính. Một trong những thách thức lớn nhất trong các trung tâm dữ liệu này là giữ cho tất cả các giá đỡ máy chủ được đóng gói chặt chẽ này đủ mát để chúng không tự làm hỏng. Chúng tôi có thể thiết lập nhiều nhiệt kế trong trung tâm dữ liệu của mình để đảm bảo rằng chúng tôi không bị quá nóng ở bất kỳ đâu và gửi kết quả đọc từ các nhiệt kế này đến máy tính trung tâm dưới dạng một luồng liên tục.

Lộ trình học đồng thời Python

Trong trạm điều khiển trung tâm của chúng tôi, chúng tôi có thể thiết lập chương trình RxPy để quan sát luồng thông tin nhiệt độ liên tục này. Trong những người quan sát này, sau đó chúng tôi có thể xác định một loạt các sự kiện có điều kiện để lắng nghe và sau đó phản ứng bất cứ khi nào một trong những điều kiện này bị tấn công

Một ví dụ như vậy sẽ là một sự kiện chỉ kích hoạt nếu nhiệt độ của một phần cụ thể của trung tâm dữ liệu trở nên quá ấm. Khi sự kiện này được kích hoạt, thì chúng tôi có thể tự động phản ứng và tăng lưu lượng của bất kỳ hệ thống làm mát nào đến khu vực cụ thể đó và do đó giảm nhiệt độ trở lại.

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())

Phá vỡ nó

Hai dòng mã đầu tiên của chúng tôi nhập mô-đun

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
1 cần thiết, sau đó từ nhập cả người quan sát và người quan sát.

Sau đó, chúng tôi tiếp tục tạo một lớp

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
2 mở rộng bộ quan sát. Lớp này chứa ba chức năng

  • import turtle
    turtle.setup(500,500) 
    window = turtle.Screen() 
    window.title("Event Handling 101")
    window.bgcolor("lightblue")
    nathan = turtle.Turtle() 
    def moveForward():
    nathan.forward(50)
    def moveLeft():
    nathan.left(30)
    def moveRight():
    nathan.right(30)
    def start(): 
    window.onkey(moveForward, "Up")
    window.onkey(moveLeft, "Left")
    window.onkey(moveRight, "Right")
    window.listen()
    window.mainloop()
    if __name__ == '__main__':
    start()
    3. Điều này được gọi mỗi khi người quan sát của chúng tôi quan sát một cái gì đó mới
  • import turtle
    turtle.setup(500,500) 
    window = turtle.Screen() 
    window.title("Event Handling 101")
    window.bgcolor("lightblue")
    nathan = turtle.Turtle() 
    def moveForward():
    nathan.forward(50)
    def moveLeft():
    nathan.left(30)
    def moveRight():
    nathan.right(30)
    def start(): 
    window.onkey(moveForward, "Up")
    window.onkey(moveLeft, "Left")
    window.onkey(moveRight, "Right")
    window.listen()
    window.mainloop()
    if __name__ == '__main__':
    start()
    4. Điều này hoạt động như chức năng xử lý lỗi của chúng tôi;
  • import turtle
    turtle.setup(500,500) 
    window = turtle.Screen() 
    window.title("Event Handling 101")
    window.bgcolor("lightblue")
    nathan = turtle.Turtle() 
    def moveForward():
    nathan.forward(50)
    def moveLeft():
    nathan.left(30)
    def moveRight():
    nathan.right(30)
    def start(): 
    window.onkey(moveForward, "Up")
    window.onkey(moveLeft, "Left")
    window.onkey(moveRight, "Right")
    window.listen()
    window.mainloop()
    if __name__ == '__main__':
    start()
    5 . T his được gọi khi người quan sát của chúng ta gặp phần cuối của luồng thông tin mà nó đang quan sát

Trong hàm

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
3, chúng tôi muốn nó in ra nhiệt độ hiện tại và cũng để kiểm tra xem nhiệt độ mà nó nhận được có nằm trong giới hạn đã đặt hay không. Nếu nhiệt độ phù hợp với một trong các điều kiện của chúng tôi, thì chúng tôi sẽ xử lý nhiệt độ hơi khác một chút và in ra các lỗi mô tả về những gì đã xảy ra

Sau khi khai báo lớp, chúng tôi tiếp tục tạo một observable giả chứa 10 giá trị riêng biệt bằng cách sử dụng

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
7, và cuối cùng, dòng cuối cùng của mã trước đó của chúng tôi sau đó đăng ký một thể hiện của lớp
import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
2 mới của chúng tôi cho observable này

 

lập trình GPU


GPU nổi tiếng với khả năng hiển thị trò chơi điện tử hành động độ phân giải cao, nhanh chóng. Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà. . Chúng có thể kết hợp hàng triệu phép tính cần thiết mỗi giây để đảm bảo rằng mọi đỉnh của mô hình 3D trong trò chơi của bạn đều ở đúng vị trí và chúng được cập nhật vài mili giây một lần để đảm bảo tốc độ 60 FPS mượt mà.

Nói chung, GPU cực kỳ giỏi trong việc thực hiện song song cùng một tác vụ, hàng triệu triệu lần mỗi phút. Nhưng nếu GPU hoạt động hiệu quả như vậy thì tại sao chúng ta không sử dụng chúng thay vì CPU? . CPU có ít lõi hơn, được thiết kế đặc biệt cho tốc độ khi chuyển ngữ cảnh giữa các tác vụ đang vận hành. Nếu các GPU được giao các nhiệm vụ giống nhau, bạn sẽ thấy hiệu suất tổng thể của máy tính bị suy giảm đáng kể

Nhưng làm thế nào chúng ta có thể sử dụng những card đồ họa mạnh mẽ này cho một thứ khác ngoài lập trình đồ họa? . Các thư viện này cố gắng trừu tượng hóa mã cấp thấp phức tạp mà API đồ họa phải tương tác để sử dụng GPU. Chúng giúp chúng tôi tái sử dụng hàng nghìn lõi xử lý nhỏ hơn có sẵn trên GPU và sử dụng chúng cho các chương trình tốn kém về mặt tính toán của chúng tôi đơn giản hơn rất nhiều

Lộ trình học đồng thời Python

Những Đơn vị xử lý đồ họa ( GPU ) gói gọn mọi thứ . Chúng có khả năng song song hóa cao và được xây dựng để đạt thông lượng tối đa. Bằng cách sử dụng những thứ này trong Python, chúng tôi có thể tận dụng tối đa cả hai thế giới. Chúng tôi có thể sử dụng một ngôn ngữ được hàng triệu người ưa chuộng do tính dễ sử dụng của ngôn ngữ này, đồng thời làm cho các chương trình của chúng tôi hoạt động hiệu quả đến không ngờ. that scripting languages are not. They are highly parallelizable, and built for maximum throughput. By utilizing these in Python, we are able to get the best of both worlds. We can utilize a language that is favored by millions due to its ease of use, and also make our programs incredibly performant.

Trong các phần sau, chúng ta sẽ xem xét các thư viện khác nhau có sẵn cho chúng ta, những thư viện này cho thấy sức mạnh của GPU

PyCUDA

PyCUDA cho phép chúng tôi tương tác với API tính toán song song CUDA của Nvidia bằng Python. Nó cung cấp cho chúng tôi rất nhiều lợi thế khác nhau so với các khung khác sử dụng cùng một API CUDA cơ bản. Những lợi thế này bao gồm những thứ như tốc độ cơ bản ấn tượng, kiểm soát hoàn toàn API trình điều khiển của CUDA và quan trọng nhất là rất nhiều tài liệu hữu ích để giúp những người mới bắt đầu sử dụng nó.

Tuy nhiên, thật không may, hạn chế chính của PyCUDA là nó sử dụng API dành riêng cho Nvidia và do đó, nếu bạn không có cạc đồ họa dựa trên Nvidia, thì bạn sẽ không thể tận dụng lợi thế của nó. Tuy nhiên, có những lựa chọn thay thế khác hoạt động tốt như nhau trên các card đồ họa không phải của Nvidia khác

OpenCL

OpenCL là một ví dụ về an thay thế cho PyCUDA và trên thực tế, tôi muốn giới thiệu điều này thay vì PyCUDA do phạm vi ấn tượng của nó . OpenCL ban đầu được hình thành bởi Apple và cho phép chúng tôi tận dụng một số nền tảng không đồng nhất như CPU, GPU, bộ xử lý tín hiệu số, mảng cổng lập trình trường và các loại bộ xử lý và bộ tăng tốc phần cứng khác. does also include Nvidia. OpenCL was originally conceived by Apple, and allows us to take advantage of a number of heterogeneous platforms such as CPUs, GPUs, digital signal processors, field-programmable gate arrays, and other different types of processors and hardware accelerators.

Hiện tại có các API của bên thứ ba không chỉ cho Python mà còn cho Java và. NET, và do đó, nó lý tưởng cho các nhà nghiên cứu và những người trong chúng ta, những người muốn sử dụng toàn bộ sức mạnh của máy tính để bàn của mình

theano

Theano là một ví dụ khác về thư viện cho phép bạn sử dụng GPU cũng như . speeds that rival C implementations when trying to solve problems that involve huge quantities of data.

Tuy nhiên, đó là một phong cách lập trình khác, theo nghĩa Python là phương tiện trong đó bạn tạo các biểu thức có thể được chuyển vào .

Ghi chú

Trang web chính thức của Theano có thể được tìm thấy ở đây. http. //học kĩ càng. net/phần mềm/theano/

 

Hạn chế của Python


Đầu chương, tôi đã nói về về những hạn chế của GIL or the Global Interpreter Lock that is present within Python, but what does this actually mean?

Đầu tiên, tôi nghĩ điều quan trọng là phải biết chính xác GIL làm gì cho chúng ta. GIL về cơ bản là một khóa loại trừ tương hỗ để ngăn nhiều luồng thực thi mã Python song song. Đó là một khóa chỉ có thể được giữ bởi một luồng tại một thời điểm và nếu bạn muốn một luồng thực thi mã của chính nó, thì trước tiên nó phải có được khóa trước khi có thể tiến hành thực thi mã của chính nó. Ưu điểm mà điều này mang lại cho chúng tôi là trong khi nó bị khóa, không có gì khác có thể chạy cùng lúc.

Lộ trình học đồng thời Python

Trong sơ đồ trước, chúng ta thấy một ví dụ về cách nhiều luồng bị cản trở bởi GIL này. Mỗi luồng phải đợi và lấy GIL trước khi có thể tiến xa hơn, sau đó giải phóng GIL, thường là trước khi nó có cơ hội hoàn thành công việc của mình. Nó tuân theo cách tiếp cận vòng tròn ngẫu nhiên và bạn không có gì đảm bảo về việc luồng nào sẽ nhận được khóa trước

Tại sao điều này là cần thiết, bạn có thể hỏi? . Nhưng nó đã được triển khai với mục đích tốt và để chống lại việc quản lý bộ nhớ Python an toàn không theo luồng. Nó ngăn chúng ta tận dụng các hệ thống đa bộ xử lý trong một số tình huống nhất định

Guido Van Rossum, người tạo ra Python, đã đăng một bản cập nhật về việc xóa GIL và các lợi ích của nó trong một bài đăng tại đây. http. //www. nghệ thuật. com/weblog/viewpost. jsp?thread=214235. Anh ấy tuyên bố rằng anh ấy sẽ không chống lại ai đó tạo ra một nhánh Python không có GIL và anh ấy sẽ chấp nhận hợp nhất mã này nếu, .

Trước đây đã có những nỗ lực loại bỏ GIL, nhưng người ta nhận thấy rằng việc bổ sung tất cả các khóa bổ sung để đảm bảo an toàn cho luồng thực sự đã làm chậm một ứng dụng hơn hai lần. Nói cách khác, bạn sẽ có thể hoàn thành nhiều công việc hơn với một CPU so với chỉ với hơn hai CPU. Tuy nhiên, có những thư viện như NumPy có thể làm mọi thứ họ cần mà không cần phải tương tác với GIL và hoạt động hoàn toàn bên ngoài GIL là điều tôi sẽ khám phá sâu hơn trong các chương sau của cuốn sách này

Cũng cần lưu ý rằng có những triển khai Python khác, chẳng hạn như Jython và IronPython, không có bất kỳ hình thức Khóa phiên dịch toàn cầu nào và như vậy có thể khai thác triệt để các hệ thống đa bộ xử lý. Jython và IronPython đều chạy trên các máy ảo khác nhau, vì vậy, chúng có thể tận dụng môi trường thời gian chạy tương ứng của chúng

Jython

Jython là một triển khai của Python hoạt động trực tiếp với nền tảng Java. Nó có thể được sử dụng theo kiểu bổ sung với Java dưới dạng ngôn ngữ kịch bản và đã được chứng minh là vượt trội so với CPython, đó là the standard implementation of Python, when working with some large datasets. For the majority of stuff though, CPython's single-core execution typically outperforms Jython and its multicore approach.

Lợi thế khi sử dụng Jython là bạn có thể thực hiện một số điều thú vị với nó khi làm việc trong Java, chẳng hạn như nhập các thư viện và khung công tác Java hiện có và sử dụng chúng như thể chúng là một phần của mã Python của bạn

Trăn sắt

IronPython là. NET tương đương với Jython hoạt động trên top của Microsoft. Nền tảng NET. Một lần nữa, bạn sẽ có thể sử dụng nó theo cách bổ sung với. ứng dụng NET. Điều này phần nào có lợi cho. NET, vì họ có thể sử dụng Python như một ngôn ngữ kịch bản nhanh và biểu cảm trong. ứng dụng NET.

Tại sao chúng ta nên sử dụng Python?

Nếu Python có những hạn chế rõ ràng, đã biết như vậy khi nói đến việc viết các ứng dụng đồng thời, có hiệu suất cao, thì tại sao chúng ta lại tiếp tục sử dụng nó? . Đó là một ngôn ngữ trực quan, dễ tiếp thu và hiểu đối với những người không nhất thiết phải có nhiều kinh nghiệm lập trình.

Ngôn ngữ này đã nhận được tỷ lệ chấp nhận rất lớn giữa các nhà khoa học dữ liệu và nhà toán học làm việc trong các lĩnh vực cực kỳ thú vị như học máy và phân tích định lượng, những người nhận thấy ngôn ngữ này là một công cụ cực kỳ hữu ích trong kho vũ khí của họ

Trong cả hệ sinh thái Python 2 và 3, bạn sẽ tìm thấy một số lượng lớn thư viện được thiết kế dành riêng cho các trường hợp sử dụng này và bằng cách biết về các hạn chế của Python, chúng tôi có thể giảm thiểu chúng một cách hiệu quả và tạo ra phần mềm hiệu quả và có khả năng thực hiện

Vì vậy, bây giờ chúng ta đã hiểu luồng và quy trình là gì, cũng như một số hạn chế của Python, đã đến lúc xem xét cách chúng ta có thể sử dụng đa luồng trong ứng dụng của mình để cải thiện tốc độ của chương trình

 

Tải xuống hình ảnh đồng thời


Không còn nghi ngờ gì nữa, một ví dụ tuyệt vời về lợi ích của đa luồng là việc sử dụng nhiều luồng để tải xuống nhiều hình ảnh hoặc tệp. Trên thực tế, đây là một trong những trường hợp sử dụng tốt nhất cho đa luồng do tính chất chặn của I/O.

Để làm nổi bật mức tăng hiệu suất, chúng tôi sẽ truy xuất 10 hình ảnh khác nhau từ http. // lorempixel. com/400/200/sports, đây là một API miễn phí cung cấp một hình ảnh khác mỗi khi bạn nhấn vào liên kết đó. Sau đó, chúng tôi sẽ lưu trữ 10 hình ảnh khác nhau này trong một thư mục tạm thời để chúng tôi có thể xem/sử dụng chúng sau này

Tất cả mã được sử dụng trong các ví dụ này có thể được tìm thấy trong kho lưu trữ GitHub của tôi tại đây. https. //github. com/elliotforbes/Concurrency-With-Python .

Tải xuống tuần tự

Đầu tiên, chúng ta nên có một số mẫu của đường cơ sở mà chúng ta có thể measure the performance gains. To do this, we'll write a quick program that will tải xuống 10 hình ảnh này liên tục như sau.

import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()

Phá vỡ nó

Trong mã trước, chúng tôi bắt đầu bằng cách nhập

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
9. Điều này sẽ đóng vai trò là phương tiện của chúng tôi để thực hiện các yêu cầu HTTP cho hình ảnh mà chúng tôi muốn. Sau đó, chúng tôi định nghĩa một hàm mới có tên là
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
0, hàm này nhận hai tham số,
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
1 và
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
2.
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
1 đại diện cho hình ảnh URL đường dẫn mà chúng tôi muốn tải xuống.
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
2 đại diện cho tên của tệp mà chúng tôi muốn sử dụng để lưu hình ảnh này cục bộ.

Trong hàm

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
5, sau đó chúng ta bắt đầu một vòng lặp
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
6. Trong vòng lặp
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
6 này, chúng tôi tạo một
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
8 bao gồm thư mục
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
9, một chuỗi đại diện cho bước lặp mà chúng tôi hiện đang thực hiện-- str ( i)--and the file extension
import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
0. We then call the
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
0 function, passing in the
import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
2 location, which provides us with a random image as well as our newly generated
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
8.

Khi chạy tập lệnh này, bạn sẽ thấy thư mục

import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
4 của mình được lấp đầy liên tục với 10 hình ảnh riêng biệt

tải xuống đồng thời

Bây giờ chúng tôi đã có cơ sở của mình, đã đến lúc viết một chương trình nhanh rằng sẽ đồng thời tải xuống tất cả các hình ảnh mà chúng tôi yêu cầu. Chúng ta sẽ tiếp tục tạo và bắt đầu chủ đề trong các chương sau, vì vậy đừng lo lắng nếu bạn gặp khó khăn trong việc hiểu mã. Điểm mấu chốt của việc này là nhận ra hiệu suất tiềm năng đạt được khi viết chương trình đồng thời.

import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()

Phá vỡ nó

Trong dòng đầu tiên của chương trình mới được sửa đổi của chúng tôi, bạn sẽ thấy rằng chúng tôi hiện đang nhập mô-đun phân luồng; . Sau đó, chúng tôi trừu tượng hóa việc tạo tên tệp của chúng tôi và gọi hàm

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
0 thành hàm
import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
6 của riêng chúng tôi.

Trong hàm

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
5, trước tiên chúng ta tạo một mảng luồng trống, sau đó lặp lại 10 lần, tạo một đối tượng luồng mới, nối thêm đối tượng này vào mảng luồng của chúng ta, rồi bắt đầu luồng đó

Cuối cùng, chúng tôi lặp qua mảng luồng của mình bằng cách gọi i trong luồng và gọi phương thức

import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
8 trên mỗi luồng này. Điều này đảm bảo rằng chúng tôi không tiến hành thực thi mã còn lại của mình cho đến khi tất cả các chuỗi của chúng tôi tải xuống xong hình ảnh.

Nếu bạn thực hiện điều này trên máy của mình, bạn sẽ thấy rằng nó gần như bắt đầu tải xuống 10 hình ảnh khác nhau ngay lập tức. Khi quá trình tải xuống hoàn tất, nó lại in ra thông báo rằng quá trình tải xuống đã hoàn tất thành công và bạn sẽ thấy thư mục

import urllib.request
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
def main():
for i in range(10):
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)

if __name__ == '__main__':
main()
4 chứa những hình ảnh này

Cả hai tập lệnh trước đều thực hiện chính xác các tác vụ giống nhau bằng cách sử dụng chính xác cùng một thư viện

import turtle
turtle.setup(500,500) 
window = turtle.Screen() 
window.title("Event Handling 101")
window.bgcolor("lightblue")
nathan = turtle.Turtle() 
def moveForward():
nathan.forward(50)
def moveLeft():
nathan.left(30)
def moveRight():
nathan.right(30)
def start(): 
window.onkey(moveForward, "Up")
window.onkey(moveLeft, "Left")
window.onkey(moveRight, "Right")
window.listen()
window.mainloop()
if __name__ == '__main__':
start()
9, nhưng nếu bạn xem xét tổng thời gian thực hiện, thì bạn sẽ thấy mức độ cải thiện về thời gian dành cho tập lệnh đồng thời tìm nạp tất cả 10 hình ảnh

 

Cải thiện xử lý số bằng đa xử lý


Vì vậy, chúng tôi đã biết chính xác cách chúng tôi có thể cải thiện những thứ như tải xuống hình ảnh, nhưng làm thế nào để chúng tôi cải thiện hiệu suất của số của chúng tôi .

Trong ví dụ này, chúng ta sẽ cố gắng tìm các thừa số nguyên tố của 10.000 số ngẫu nhiên nằm trong khoảng từ 20.000 đến 100.000.000. Chúng tôi không nhất thiết phải lo lắng về thứ tự thực hiện miễn là công việc được hoàn thành và chúng tôi không chia sẻ bộ nhớ giữa bất kỳ quy trình nào của chúng tôi

Thừa số nguyên tố tuần tự

Một lần nữa, chúng ta sẽ viết một tập lệnh thực hiện điều này theo cách tuần tự mà chúng ta . easily verify is working correctly:

import time
import random
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
def main():
print("Starting number crunching")
t0 = time.time()

for i in range(10000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))

t1 = time.time()
totalTime = t1 - t0
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()

Phá vỡ nó

Hai dòng đầu tiên tạo nên các lần nhập bắt buộc của chúng tôi--chúng tôi sẽ cần cả thời gian và các mô-đun ngẫu nhiên. Sau khi nhập xong, chúng ta tiếp tục xác định hàm

import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
1, hàm này nhận đầu vào là n . Điều này tính toán hiệu quả tất cả các thừa số nguyên tố của một số đã cho và nối chúng vào một mảng, sau đó được trả về sau khi hàm đó hoàn tất thực thi.

Sau đó, chúng tôi xác định hàm

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
5, tính toán thời gian bắt đầu và sau đó quay vòng qua 10.000 số, được tạo ngẫu nhiên bằng cách sử dụng hàm ngẫu nhiên
import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
3. Sau đó, chúng tôi chuyển các số được tạo này tới hàm
import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
1 và chúng tôi in ra kết quả. Cuối cùng, chúng tôi tính toán thời gian kết thúc của vòng lặp
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
6 này và in nó ra

Nếu bạn thực hiện điều này trên máy tính của mình, bạn sẽ thấy mảng các thừa số nguyên tố được in ra cho 10.000 số ngẫu nhiên khác nhau, cũng như tổng thời gian thực hiện cho mã này. Đối với tôi, nó mất khoảng 3. 6 giây để thực hiện trên Macbook của tôi

Thừa số nguyên tố đồng thời

Vì vậy, bây giờ chúng ta hãy xem cách chúng tôi có thể cải thiện hiệu suất của chương trình này bằng cách sử dụng nhiều quy trình.

Để chia nhỏ khối lượng công việc này, chúng tôi sẽ xác định một hàm

import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
6, thay vào đó, của tạo ra 10.000 số ngẫu nhiên cho . Tuy nhiên, chúng ta sẽ tạo 10 quy trình và thực thi hàm 10 lần, do đó, tổng số của tính toán phải giống hệt như khi chúng ta thực hiện .

import time
import random
from multiprocessing import Process
# This does all of our prime factorization on a given number 'n'
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
# We split our workload from one batch of 10,000 calculations
# into 10 batches of 1,000 calculations
def executeProc():
for i in range(1000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))
def main():
print("Starting number crunching")
t0 = time.time() 
procs = []
# Here we create our processes and kick them off
for i in range(10):
proc = Process(target=executeProc, args=())
procs.append(proc)
proc.start()
# Again we use the .join() method in order to wait for 
# execution to finish for all of our processes
for proc in procs:
proc.join()
t1 = time.time()
totalTime = t1 - t0
# we print out the total execution time for our 10
# procs.
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()

Phá vỡ nó

Mã cuối cùng này thực hiện chính xác chức năng như mã được đăng ban đầu của chúng tôi. Tuy nhiên, thay đổi đầu tiên là ở dòng ba. Ở đây, chúng tôi nhập quy trình từ mô-đun đa xử lý. Sau đây của chúng tôi, phương pháp

import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
1 chưa được chạm vào.

Sau đó, bạn sẽ thấy rằng chúng tôi đã rút ra vòng lặp

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
6 ban đầu chạy trong 10.000 lần lặp. Bây giờ chúng tôi đã đặt cái này trong một hàm có tên là
import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
6 và chúng tôi cũng đã giảm phạm vi vòng lặp
import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
6 của mình xuống còn 1.000

Trong hàm

import rx
from rx import Observable, Observer
# Here we define our custom observer which
# contains an on_next method, an on_error method
# and an on_completed method
class temperatureObserver(Observer):
# Every time we receive a temperature reading
# this method is called
def on_next(self, x):
print("Temperature is: %s degrees centigrade" % x)
if (x > 6):
print("Warning: Temperate Is Exceeding Recommended Limit")
if (x == 9):
print("DataCenter is shutting down. Temperature is too high")
# if we were to receive an error message
# we would handle it here
def on_error(self, e):
print("Error: %s" % e)

# This is called when the stream is finished
def on_completed(self):
print("All Temps Read")
# Publish some fake temperature readings 
xs = Observable.from_iterable(range(10))
# subscribe to these temperature readings
d = xs.subscribe(temperatureObserver())
5, sau đó chúng ta tạo một mảng trống có tên là
import time
import random
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
def main():
print("Starting number crunching")
t0 = time.time()

for i in range(10000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))

t1 = time.time()
totalTime = t1 - t0
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()
2. Sau đó, chúng tôi tạo 10 quy trình khác nhau và đặt mục tiêu là hàm
import threading
import urllib.request
import time
def downloadImage(imagePath, fileName):
print("Downloading Image from ", imagePath)
urllib.request.urlretrieve(imagePath, fileName)
print("Completed Download")
def executeThread(i): 
imageName = "temp/image-" + str(i) + ".jpg"
downloadImage("http://lorempixel.com/400/200/sports", imageName)
def main():
t0 = time.time()
# create an array which will store a reference to
# all of our threads
threads = []
# create 10 threads, append them to our array of threads
# and start them off
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()

# ensure that all the threads in our array have completed
# their execution before we log the total time to complete
for i in threads:
i.join()
# calculate the total execution time
t1 = time.time()
totalTime = t1 - t0
print("Total Execution Time {}".format(totalTime))
if __name__ == '__main__':
main()
6 và không chuyển vào đối số. Chúng tôi nối quy trình mới được tạo này vào mảng
import time
import random
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
def main():
print("Starting number crunching")
t0 = time.time()

for i in range(10000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))

t1 = time.time()
totalTime = t1 - t0
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()
2 của chúng tôi và sau đó chúng tôi bắt đầu quy trình bằng cách gọi
import time
import random
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
def main():
print("Starting number crunching")
t0 = time.time()

for i in range(10000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))

t1 = time.time()
totalTime = t1 - t0
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()
5

Sau khi chúng tôi đã tạo 10 quy trình riêng lẻ, sau đó chúng tôi sẽ chuyển qua các quy trình này hiện có trong mảng

import time
import random
def calculatePrimeFactors(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d)# supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
def main():
print("Starting number crunching")
t0 = time.time()

for i in range(10000):
rand = random.randint(20000, 100000000)
print(calculatePrimeFactors(rand))

t1 = time.time()
totalTime = t1 - t0
print("Execution Time: {}".format(totalTime))
if __name__ == '__main__':
main()
2 của chúng tôi và tham gia chúng. Điều này đảm bảo rằng mọi quy trình đã hoàn thành các tính toán của nó trước khi chúng tôi tiến hành tính tổng thời gian thực hiện

Nếu bạn thực hiện điều này ngay bây giờ, bạn sẽ thấy 10.000 đầu ra hiện được in ra trong bảng điều khiển của mình và bạn cũng sẽ thấy thời gian thực hiện thấp hơn nhiều so với thực thi tuần tự của mình. Để tham khảo, chương trình tuần tự được thực hiện trong 3. 9 giây trên máy tính của tôi so với 1. 9 giây khi chạy phiên bản đa xử lý

Đây chỉ là minh họa rất cơ bản về cách chúng ta có thể triển khai đa xử lý vào các ứng dụng của mình. Trong các chương sau, chúng ta sẽ khám phá cách chúng ta có thể tạo nhóm và sử dụng bộ thực thi. Điểm mấu chốt cần rút ra từ điều này là chúng ta có thể cải thiện hiệu suất của một số tác vụ liên quan đến CPU bằng cách sử dụng nhiều lõi

 

Bản tóm tắt


Bây giờ, bạn đã hiểu rõ một số khái niệm cơ bản làm nền tảng cho lập trình đồng thời. Bạn nên nắm bắt các luồng, quy trình và bạn cũng sẽ biết một số hạn chế và thách thức của Python khi triển khai các ứng dụng đồng thời của riêng bạn. Cuối cùng, bạn cũng đã tận mắt chứng kiến ​​một số cải tiến về hiệu suất mà bạn có thể đạt được nếu bạn thêm các loại đồng thời khác nhau vào ứng dụng của mình

Bây giờ tôi phải làm rõ rằng không có viên đạn bạc nào mà bạn có thể áp dụng cho mọi ứng dụng và nhận thấy những cải thiện hiệu suất nhất quán. Một kiểu lập trình đồng thời có thể hoạt động tốt hơn kiểu khác tùy thuộc vào yêu cầu của ứng dụng của bạn, vì vậy trong vài chương tiếp theo, chúng ta sẽ xem xét tất cả các cơ chế khác nhau mà bạn có thể sử dụng và thời điểm sử dụng chúng

Trong chương tiếp theo, chúng ta sẽ có cái nhìn sâu hơn về khái niệm đồng quy và song song, cũng như sự khác biệt giữa hai khái niệm này. Chúng ta cũng sẽ xem xét một số tắc nghẽn chính hạn chế các hệ thống đồng thời của chúng ta và bạn sẽ tìm hiểu các kiểu kiến ​​trúc hệ thống máy tính khác nhau cũng như cách nó có thể giúp chúng ta đạt được hiệu suất cao hơn

Python có tốt cho đồng thời không?

Python cung cấp cơ chế cho cả đồng thời và song song , mỗi cơ chế có cú pháp và trường hợp sử dụng riêng. Python có hai cơ chế khác nhau để triển khai đồng thời, mặc dù chúng chia sẻ nhiều thành phần chung. Đây là luồng và coroutines hoặc không đồng bộ.

Đồng thời hoạt động như thế nào trong Python?

Định nghĩa đồng thời trong từ điển là sự xuất hiện đồng thời. Trong Python, những thứ xảy ra đồng thời được gọi bằng các tên khác nhau (luồng, tác vụ, quy trình) nhưng ở cấp độ cao, chúng đều đề cập đến một chuỗi các lệnh chạy theo thứ tự . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Lộ trình học Python là gì?

Mọi thứ từ kiến ​​thức cơ bản tuyệt đối về Python, đến phát triển web và quét web, đến trực quan hóa dữ liệu và hơn thế nữa . Cho dù bạn là một Pythonista mới bắt đầu, trung cấp hay cao cấp, Lộ trình học tập tùy chỉnh của chúng tôi sẽ đưa các kỹ năng của bạn lên một tầm cao mới với một kế hoạch học tập thực hành, cấp tốc.

Đồng thời Python có phải là một luồng không?

Python KHÔNG phải là ngôn ngữ đơn luồng . Các quy trình Python thường sử dụng một luồng đơn vì GIL. Bất chấp GIL, các thư viện thực hiện các tác vụ tính toán nặng như numpy, scipy và pytorch sử dụng các triển khai dựa trên C dưới mui xe, cho phép sử dụng nhiều lõi.