Signal trong Python

Tram Ho

Signal

UNIX/Linux systems cung cấp các cơ chế đặc biệt để communicate giữa các process. Một trong số đó lấy tên là signals.

Một cách ngắn gọn, a signal giống như một notification của một event. Khi một event nào đó xảy ra trong system, một signal sẽ được tạo ra để notify tới các chương trình khác về event này.

Một ví dụ đơn giản: Khi bạn đang run một command trên terminal. Câu lệnh đang chạy, mà bạn lại sử dụng tổ hợp phím ctrl + C . Khi đó, một signal được gọi là SIGINT sinh ra. Và chương trình terminal sẽ đọc tín hiệu đó và thực thi việc dừng command lại.

Trên UNIX-based systems, sẽ có 3 loại signals chính:

  • System signals:
    • SIGILL
    • SIGTRAP
    • SIGBUS
    • SIGFPE,
    • SIGKILL
    • SIGSEGV
    • SIGXCPU
    • SIGXFSZ
    • SIGIO
  • Device signals:
    • SIGHUP
    • SIGINT
    • SIGPIPE
    • SIGALRM
    • SIGCHLD
    • SIGCONT
    • SIGSTOP
    • SIGTTIN
    • SIGTTOU
    • SIGURG
    • SIGWINCH
    • SIGIO
  • User-defined signals:
    • SIGQUIT
    • SIGABRT
    • SIGUSR1
    • SIGUSR2
    • SIGTERM

Mỗi một signal sẽ được đại diện bởi một integer value.

Trên Ubuntu, bạn có thể check list signal này :

Khi thực hiện lệnh man 7 signal, bạn cũng sẽ thể thấy cách sử dụng signal trong Ubuntu nó như thế nào:

Python signal

Từ bản Python 1.4, signal library đã được tích hợp và cập nhật thường xuyên vào trong core.

Python Basic

Một ví dụ nhỏ về sử dụng SIGINT signal:

Line 1, 2 sẽ import lib signal và lib time.

Line 5, 6 define function handle signal. Trong function này mình sẽ print ra value integer của signal và frame mà nó nhận được cùng với signal.

Line 8 sử dụng signal.signal() function để assign handle signal SIGINT. Mỗi một khoảng thời gian, CPU nhận được ctrl + c, function handler lại được thực hiện.

Line 10, 11, 12 sử dụng while True để chương trình luôn chạy.

Lưu đoạn code trên mà test thử :

Trên đây là ví dụ rất đơn giản về sử dụng sinal trong Python basic.

Django

Django cung cấp các signal dispatcher. Nó cho phép các app tách rời được notified khi các action xảy ra ở nơi khác trong framework.

Các signal built-in trong Django:

  • django.db.models.signals.pre_save & django.db.models.signals.post_save: Send trước hoặc sau khi save() method được thực hiện trong model.
  • django.db.models.signals.pre_delete & django.db.models.signals.post_delete: Send trước hoặc sau khi delete() method được thực hiện trong model.
  • django.db.models.signals.m2m_changed: Sent khiManyToManyField on a model is changed.
  • django.core.signals.request_started & django.core.signals.request_finished: Sent khi Django starts or finishes một HTTP request.

Trong django, sử dụng Signal.connect() method để đăng ký một receiver function. receiver function này được called khi một signal được sent. Toàn bộ các signal’s receiver functions được gọi ở cùng một thời điểm và dựa theo thứ tự đăng ký.

Bài toán dưới đây là thực hiện in ra dòng chữ Request finished! trên console sau mõi request được hoàn thành.

Receiver functions

Đầu tiên, receiver được define như thế nào ?

Lưu ý, trong hàm receiver phải có sender argument. Các arguments khác sẽ cần phải đẩy vào **kwargs.

Connecting receiver functions

Có 2 syntax cho phép connect a receiver to a signal.

  • Option1: sử dụng request_finished.connect().

  • Option2: sử dụng receiver() decorator.

Sau khi setup xong, my_callback function sẽ được call mỗi khi request finish.

Với bài toán trên, toàn bộ các requests finish thì sẽ đều bắn ra một signal. Vậy với bài toán, mình sẽ chỉ bắn signal với case cụ thể thì sao ?

Connecting to signals sent by specific senders

Trong bài toán đăng ký user. Giải sử mình có một model User. Sau khi save user info vào model, mình muốn send thông báo rằng “Bạn đã đăng ký thành công” chẳng hạn.

Minh sẽ cần sử dụng signal built-in : from django.db.models.signals import post_save

Summary

Trong article này, mình đã hướng dẫn các bạn hiểu signal là gì ? Cách sử dụng signal trong Python nói chung và trong Django nói riêng.

Thanks for reading!

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo