Я хотел бы кратко рассказать о некоторых базовых модулях python, предназначенных для работы с потоками, процессами, сокетами, пайпами и тому подобное.
Потоки.
В одно процессе может одновременно работать несколько потоков. Для организации доступа нескольких потков к одним данным python использует global interpreter lock.
-
import threading #higher-level interface
-
import time, random
-
class Counter:
-
def __init__(self):
-
self.lock = threading.Lock()
-
# создается объект блокировки данных
-
self.value = 0
-
def increment(self):
-
self.lock.acquire() # блокировка
-
self.value = value = self.value + 1 # изменение каких либо данных
-
self.lock.release() # разблокировка
-
return value
-
counter = Counter()
-
class Worker(threading.Thread): #класс потока
-
def run(self): # этот метод выполняется во время работы потока
-
for i in range(10):
-
# изменение общих данных внутри потока
-
value = counter.increment()
-
time.sleep(random.randint(10, 100) / 1000.0)
-
print self.getName(), "– task", i, "finished", value
-
-
for i in range(10):
-
Worker().start() # start a worker
Команда
Иногда просто надо из вашей программы запустить внешнюю команду. Для этого есть модуль commands (unix only)
-
import commands
-
stat, output = commands.getstatusoutput("ls -lR")
-
# вызываем внешнюю команду. Получаем результат и статус
-
print "status", "=>", stat
-
print "output", "=>", len(output), "bytes"
Pipe.
Именованый канал. Служит для взаимодействиями между процессами. На основе этого класса можно построить конвейер взаимодействия.
-
import pipes
-
t = pipes.Template() # создаем объект пайпа
-
t.append("sort", "—-")
-
# добавляем в конец процесс sort .
-
# "–" – означает, что используется стандартный вход или выход.
-
t.append("uniq", "—-") # и еще один
-
t.copy("out.txt", "")
-
# входные данные берем из файла out.txt и отправляем в STDOUT
STDIN и STDOUT внешних комманд
Модуль popen2 позволяет работать с STDOUT и STDIN внешних процессов, как к обыкновенными файл хэндлами.
-
import popen2
-
fin, fout = popen2.popen2("sort") # запускаем внешний процесс и получаем доступы к хендлам
-
fout.write("foo\n") # записываем в процесс
-
fout.write("bar\n")
-
fout.close() # закрываем
-
print fin.readline(), # считываем строки
-
print fin.readline(), #
-
fin.close()
popen3 работает также как и popen2, только возвращает еще и хэндл STDERR
Сигналы
Процессы могут получать внешние сигналы, и необходимо иметь возможность их обрабатывать. Ниже пример того, как приложение посылает сигнал самому себе.
-
import signal
-
import time
-
def handler(signo, frame): # пишим обработчик сигнала ALRM
-
print "got signal", signo
-
signal.signal(signal.SIGALRM, handler) #
-
-
signal.alarm(2) # послать самому себе сигнал ALRM через 2 сек
-
now = time.time()
-
time.sleep(400)
-
print "slept for", time.time() – now, "seconds" # узнать, сколько я спал
Ниже пример того, как приложение посылает сигнал самому себе.
Сокеты
Это программный интерфейс, для обмена сообщениями между процессами. Ниже пример создания файлового сокет сервера
-
import SocketServer
-
import os
-
-
class MyHandler(SocketServer.StreamRequestHandler):
-
# Класс, который будет обрабатывать запросы клиентов
-
def handle(self):
-
data = self.request.recv(1000000) # Получение данных от клиента
-
print 'Data:'+data
-
self.request.send('And you') # Отправка данных клиенту
-
-
sock_path = '/tmp/unix_socket_server'
-
if os.path.exists(sock_path): # Если файл уже существует, то удоляем его перед стартом сервера
-
os.remove(sock_path)
-
server = SocketServer.UnixStreamServer(sock_path,MyHandler) # Создаем объект сервера
-
server.serve_forever() # запускаем его
И клиента:
-
import socket;
-
sock_path = '/tmp/unix_socket_server'
-
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # создание объекта клиента
-
server.connect(sock_path) # присоединяемся к указаному сокету
-
server.send('Hi!') # Отправляем данные
-
print 'GET:'+server.recv(10000) # Получаем данные.
Помимо файлового сокет сервера можно создавать TCP сервер. Где для взаимодействия используется не файловый сокет а протокол TCP/IP. Что дает возможность взаимодействовать не только локальным процессам.
Код сервера:
-
import SocketServer
-
-
class MyTCPHandler(SocketServer.StreamRequestHandler):
-
def handle(self):
-
data = self.request.recv(1000000)
-
print 'Data:'+data
-
self.request.send('And you')
-
-
-
HOST, PORT = "localhost", 9999
-
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
-
server.serve_forever()
Проверить его работу можно просто написав в командной сроке
после открытия соединение, все что вы будите писать, будет отправлятся на этот сервер по нажатию кнопки Enter.
Но это можно делать и программно. Ниже приведен код клиента:
-
import socket
-
import sys
-
-
HOST, PORT = "localhost", 9999
-
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
sock.connect((HOST, PORT))
-
-
sock.send("HI")
-
print 'GET:'+sock.recv(1024)
-
sock.close()
Как вы уже заметили, в коде эти два сервера отличаются сроками создания объекта сервера и клиента.
Также для написаниея клиента можно использовать модуль telnetlib. Не думаю, что стоит тут что либо комментировать.
-
import telnetlib
-
tl = telnetlib.Telnet('127.0.0.1',9999)
-
tl.write('HI')
-
print tl.read_all()
Для написание более сложных механизмов взаимодействия используйте Twisted. Это уже более сложная событийная модель на Python. Но перед тем как его использовать убедитесь, что это не будет стрельба из пушки по воробьям.
Надеюсь, что эта была вам интересна и полезна. А мне интересно прочитать ваше мнение, ваши примеры и трюки. А возможно я что то забыл упомянуть по теме?
Recent Comments