Thread.sleep метод

2. Режим гибернации

Режим гибернации (Hibernate, Suspend to disk) деактивирован в Ubuntu по умолчанию и предусматривает отключение питания компьютера с переносом данных из оперативной памяти в раздел подкачки. Разумеется, для корректной работы данного режима размер раздела подкачки должен превышать объём доступной оперативной памяти. Кроме того, данный режим нередко работает некорректно из-за проблем с прошивками материнских плат. Ещё один его недостаток — затраты времени на запись и чтение данных. Для активации режима гибернации необходимо добавить параметр ядра ОС и создать файл конфигурации Polkit.

Начнём с параметра ядра ОС. Он предназначен для передачи имени файла устройства раздела подкачки, в котором будут сохраняться данные состояния ОС. Чтобы узнать имя этого файла, можно воспользоваться следующей командой:

Необходимое имя должно находиться в столбце NAME (Рисунок 5).

Рисунок 5. Список разделов подкачки системы

В случае его отсутствия у вас не активирован раздел подкачки.

Это имя следует добавить в строку параметров ядра ОС, передаваемую системным загрузчиком GRUB, в форме значения параметра resume. Для этого нужно открыть файл конфигурации /etc/default/grub и отредактировать строку GRUB_CMDLINE_LINUX_DEFAULT. Проще всего это сделать с помощью следующей команды:

Предположим, что именем файла устройства раздела подкачки является /dev/sda5. Тогда строку

придёётся заменить на строку

После этого нужно сохранить изменения в открытом файле (Рисунок 6).

Рисунок 6. Измененные параметры ядра Linux

В заключение нужно обновить конфигурацию системного загрузчика с помощью следующей команды:

Помимо этого следует создать файл конфигурации Polkit в директории /etc/polkit-1/localauthority/50-local.d/ с именем com.ubuntu.enable-hibernate.pkla и следующим содержимым:

Identity=unix-user:*
Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.handle-hibernate-key;org.freedesktop.login1;org.freedesktop.login1.hibernate-multiple-sessions;org.freedesktop.login1.hibernate-ignore-inhibit
ResultActive=yes

Теперь приложение для изменения параметров системы позволит активировать режим гибернации при нажатии на кнопку включения (Рисунок 7).

Рисунок 7. Режим гибернации в меню приложения для изменения параметров системы

Это повод проверить спящий режим Ubuntu 18.04 с гибернацией. При отсутствии результата, вы можете снова деактивировать его, удалив созданный файл конфигурации с помощью команды:

Если же данный режим будет работать корректно, вы можете использовать кнопку включения для его активации. Если вы хотите активировать его при закрытии крышки ноутбука, вам придётся воспользоваться последовательностью специальных команд. Потому что ни приложение для изменения параметров системы, ни утилита GNOME Tweaks не позволёт сделать этого. Вот эти команды:

Первая команда устанавливает режим при питании компьютера от сети, вторая — от батареи. Для проверки корректности установки значений параметров конфигурации может использоваться специальная утилита с графическим интерфейсом. Она устанавливается с помощью следующей команды:

По окончании установки достаточно запустить её (имя в меню Редактор d-conf), осуществить переход org — gnome — settings-daemon — plugins — power и проверить значения параметров lid-close-ac-action и lid-close-battery-action (Рисунок 8).

Рисунок 8. Активированный режим гибернации при закрытии крышки ноутбука

Если вас не устраивает активируемый при закрытии крышки ноутбука режим гибернации, вы можете вернуть режим ожидания с помощью следующих команд:

Также может возникнуть вопрос: «А как активировать режим гибернации из системного меню?». Вообще, такой возможности не предусмотрено, но вы можете установить расширение GNOME Shell под названием «Hibernate Status Button». Установка расширения осуществляется с помощью Менеджера приложений Ubuntu (само расширение размещено в разделе Дополнения на вкладке Расширения GNOME Shell) (Рисунок 9).

Рисунок 9. Расширение «Hibernate Status Button» в списке расширений Менеджера приложений Ubuntu

После установки расширения в системном меню появится соответствующая кнопка (Рисунок 10).

Рисунок 10. Кнопка для перехода в режим гибернации

Если нажать на клавишу Alt при показе системного меню, кнопка перехода в режим гибернации будет заменена на кнопку перехода в гибридный режим сна.

Ну и о командах для самостоятельной активации данного режима. Это команда для перехода в режим гибернации с помощью утилиты systemctl:

А это вызов соответствующего метода DBus:

Метод after() — Погружение в сон для Tkinter

tkinter является частью стандартной библиотеки Python. В случае, если вы используете заранее установленную версию Python на Linux или Mac, он может быть вам недоступен. При получении ошибки стоит самостоятельно добавить его в систему. В том случае, если вы ранее установили Python сами, должен быть доступен.

Начнем с разбора примера, где используется . Запустите следующий код и посмотрите, что произойдет при неправильном добавлении вызова в Python:

Python

import tkinter
import time

class MyApp:
def __init__(self, parent):
self.root = parent
self.root.geometry(«400×400″)
self.frame = tkinter.Frame(parent)
self.frame.pack()
b = tkinter.Button(text=»click me», command=self.delayed)
b.pack()

def delayed(self):
time.sleep(3)

if __name__ == «__main__»:
root = tkinter.Tk()
app = MyApp(root)
root.mainloop()

1
2
3
4
5
6
7
8
9
10
11
12
13

15
16
17
18
19

importtkinter

importtime

classMyApp

def__init__(self,parent)

self.root=parent

self.root.geometry(«400×400»)

self.frame=tkinter.Frame(parent)

self.frame.pack()

b=tkinter.Button(text=»click me»,command=self.delayed)

b.pack()

defdelayed(self)

if__name__==»__main__»

root=tkinter.Tk()

app=MyApp(root)

root.mainloop()

После запуска кода нажмите кнопку в GUI. Кнопка не будет реагировать три секунды, ожидая завершения . Если в приложении есть другие кнопки, на них тоже нельзя будет нажать. Закрыть приложение во время сна нельзя, так как оно не будет откликаться на событие закрытия.

Для должного погружения в сон потребуется использовать :

Python

import tkinter

class MyApp:
def __init__(self, parent):
self.root = parent
self.root.geometry(«400×400»)
self.frame = tkinter.Frame(parent)
self.frame.pack()
self.root.after(3000, self.delayed)

def delayed(self):
print(‘Я задержался’)

if __name__ == «__main__»:
root = tkinter.Tk()
app = MyApp(root)
root.mainloop()

1
2
3
4
5
6
7
8

10
11
12
13
14
15
16
17

importtkinter

classMyApp

def__init__(self,parent)

self.root=parent

self.root.geometry(«400×400»)

self.frame=tkinter.Frame(parent)

self.frame.pack()

defdelayed(self)

print(‘Я задержался’)

if__name__==»__main__»

root=tkinter.Tk()

app=MyApp(root)

root.mainloop()

Здесь создается приложение, высота которого 400 пикселей, и ширина также 400 пикселей. На нем нет виджетов. Оно только показывает фрейм. Затем вызывается , где является отсылкой к объекту . принимает два аргумента:

  1. Количество миллисекунд для сна;
  2. Метод который вызовется после завершения сна.

В данном случае приложение выведет строку в стандартный поток вывода (stdout) через 3 секунды. Можно рассматривать как Tkinter-версию того же , только он добавляет способность вызова функции после завершения сна.

Данную функциональность можно использовать для улучшения работы пользователя. Добавив в Python вызов , можно ускорить процесс загрузки приложения, после чего начать какой-то длительный процесс. В таком случае пользователю не придется ждать открытия приложения.

Overloads

Suspends the current thread for the specified number of milliseconds.

Suspends the current thread for the specified amount of time.

Sleep(Int32)

Suspends the current thread for the specified number of milliseconds.

Parameters

millisecondsTimeout

Int32

The number of milliseconds for which the thread is suspended. If the value of the argument is zero, the thread relinquishes the remainder of its time slice to any thread of equal priority that is ready to run. If there are no other threads of equal priority that are ready to run, execution of the current thread is not suspended.

Exceptions

ArgumentOutOfRangeException

The time-out value is negative and is not equal to Infinite.

Examples

The following example uses the Sleep method to block the application’s main thread.

Remarks

The thread will not be scheduled for execution by the operating system for the amount of time specified. This method changes the state of the thread to include .

You can specify Timeout.Infinite for the parameter to suspend the thread indefinitely. However, we recommend that you use other System.Threading classes such as Mutex, Monitor, EventWaitHandle, or Semaphore instead to synchronize threads or manage resources.

The system clock ticks at a specific rate called the clock resolution. The actual timeout might not be exactly the specified timeout, because the specified timeout will be adjusted to coincide with clock ticks. For more information on clock resolution and the waiting time, see the Sleep function from the Windows system APIs.

This method does not perform standard COM and SendMessage pumping.

Note

If you need to sleep on a thread that has STAThreadAttribute, but you want to perform standard COM and SendMessage pumping, consider using one of the overloads of the Join method that specifies a timeout interval.

Sleep(TimeSpan)

Suspends the current thread for the specified amount of time.

Parameters

timeout

TimeSpan

The amount of time for which the thread is suspended. If the value of the argument is Zero, the thread relinquishes the remainder of its time slice to any thread of equal priority that is ready to run. If there are no other threads of equal priority that are ready to run, execution of the current thread is not suspended.

Exceptions

ArgumentOutOfRangeException

The value of is negative and is not equal to Infinite in milliseconds, or is greater than MaxValue milliseconds.

Examples

The following example uses the method overload to block the application’s main thread five times, for two seconds each time.

Remarks

The thread will not be scheduled for execution by the operating system for the amount of time specified. This method changes the state of the thread to include .

You can specify Timeout.InfiniteTimeSpan for the parameter to suspend the thread indefinitely. However, we recommend that you use other System.Threading classes such as Mutex, Monitor, EventWaitHandle, or Semaphore instead to synchronize threads or manage resources.

This overload of Sleep uses the total number of whole milliseconds in . Fractional milliseconds are discarded.

This method does not perform standard COM and SendMessage pumping.

Note

If you need to sleep on a thread that has STAThreadAttribute, but you want to perform standard COM and SendMessage pumping, consider using one of the overloads of the Join method that specifies a timeout interval.

Вызов sleep() с декораторами

В некоторых случаях нужно повторно запустить неудачно выполненную в первый раз функцию. Зачастую это происходит, когда требуется повторить загрузку файла ввиду ранней перегрузки сервера. Как правило, никто не хочет делать частые запросы на серверы, поэтому добавление в Python вызова между каждым запросом предпочтительно.

Другим возможным случаем использования является необходимость проверки состояния пользовательского интерфейса во время автоматического теста. В зависимости от компьютера, на котором запускается тест, пользовательский интерфейс может грузиться быстрее или медленнее обычного. Это может изменить отображаемое на экране во время проверки программой чего-то.

В данном случае можно указать программе, чтобы та погрузилась в сон на мгновенье и затем проверить все опять через несколько секунд. Это может означать разницу между прохождением или провалом теста.

Для добавления системного вызова в Python можно использовать декоратор в каждом из данных случаев. Разберем следующий пример:

Python

import time
import urllib.request
import urllib.error

def sleep(timeout, retry=3):
def the_real_decorator(function):
def wrapper(*args, **kwargs):
retries = 0
while retries < retry:
try:
value = function(*args, **kwargs)
if value is None:
return
except:
print(f’Сон на {timeout} секунд’)
time.sleep(timeout)
retries += 1
return wrapper
return the_real_decorator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

importtime

importurllib.request

importurllib.error

defsleep(timeout,retry=3)

defthe_real_decorator(function)

defwrapper(*args,**kwargs)

retries=

whileretries<retry

try

value=function(*args,**kwargs)

ifvalue isNone

return

except

print(f’Сон на {timeout} секунд’)

time.sleep(timeout)

retries+=1

returnwrapper

returnthe_real_decorator

является вашим декоратором. Он принимает значение и количество раз для повтора , что по умолчанию равняется 3. Внутри есть другая функция, , которая принимает декорируемую функцию.

В конечном итоге самая внутренняя функция принимает аргументы и ключевые слова, которые вы передаете декорируемой функции. Здесь все и происходит! Используется , чтобы повторить вызов функции. Если возникла ошибка, вызывается , увеличивается счетчик попыток и повторяется попытка запуска функции.

Теперь переписывается   для использования нового декоратора:

Python

@sleep(3)
def uptime_bot(url):
try:
conn = urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
# Отправка admin / log
print(f’HTTPError: {e.code} для {url}’)
# Повторное поднятие ошибки исключения для декоратора
raise urllib.error.HTTPError
except urllib.error.URLError as e:
# Отправка admin / log
print(f’URLError: {e.code} для {url}’)
# Повторное поднятие ошибки исключения для декоратора
raise urllib.error.URLError
else:
# Сайт поднят
print(f'{url} поднят’)

if __name__ == ‘__main__’:
url = ‘http://www.google.com/py’
uptime_bot(url)

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

defuptime_bot(url)

try

conn=urllib.request.urlopen(url)

excepturllib.error.HTTPError ase

# Отправка admin / log

print(f’HTTPError: {e.code} для {url}’)

# Повторное поднятие ошибки исключения для декоратора

raiseurllib.error.HTTPError

excepturllib.error.URLError ase

# Отправка admin / log

print(f’URLError: {e.code} для {url}’)

# Повторное поднятие ошибки исключения для декоратора

raiseurllib.error.URLError

else

# Сайт поднят

print(f'{url} поднят’)

if__name__==’__main__’

url=’http://www.google.com/py’

uptime_bot(url)

Здесь вы декорируете с помощью в 3 секунды. Вы также удалили оригинальный цикл и старый вызов . Декоратор теперь позаботится об этом.

Другое изменение состоит в добавлении внутри блоков, отвечающих за обработку исключений. Это нужно для правильной работы декоратора. Можно также написать декоратор, чтобы он отвечал за ошибки, однако ввиду того, что исключения касаются только , может быть лучше сохранить декоратор в текущем состоянии. В таком случае он будет работать c более широким ассортиментом функций.

Декоратору можно добавить несколько улучшений. Если число попыток заканчивается, и он по-прежнему проваливается, тогда можно сделать так, чтобы он повторно вызвал последнюю ошибку. Декоратор подождет 3 секунды после последней неудачи, что не всегда нужно. Можете попробовать поэкспериментировать самостоятельно.

Файл — это очень уж странный предмет…

Системные вызовы — это не только способ попросить ядро обратиться к оборудованию от имени процесса. Это ещё и универсальное API, понятное всем библиотекам в системе. Значит, если в библиотеке не поддержали нужную вам функциональность, возможно, она автоматически получится, если правильно попросить ядро. К тому же, часть «настроек» процесса наследуется при , поэтому таким образом можно попробовать обойтись без сложных костылей, просто правильно сформировав состояние перед запуском процесса (что-то вроде «зачем вручную перекладывать в файл, если можно просто открыть файл и сделать его FD #2 для дочернего процесса»).

Как-то раз мне потребовалось вычитать из файла последовательность сетевых пакетов. В какой-то момент количество костылей превысило все разумные пределы, и я решил, что вряд ли будет сложнее, чем то, что я написал, к тому же, это стандарт, и для открытия этих файлов существуют общепринятые инструменты. Оказалось, что пользоваться для чтения дампов примерно настолько же сложно, как и для чтения файлов: вы просто открываете дамп с помощью и вычерпываете пакеты через . Всё! Ну, ещё стоит закрыть дамп по завершению работы…

Но вот незадача: похоже, не умеет читать из памяти. Может, и умеет конечно, если покопаться, но для нашей «лабораторки» представим, что не умеет.

Итак, модельный пример: мы ждём на некую последовательность байтов, после которой идёт выровненный на 4 байта дамп. Я понимаю, что можно использовать буферизованный ввод и какой-нибудь (поскольку всё равно требует ), но в общем случае мы, может, на ходу распаковываем, например, или библиотека может непосредственно работать с / .

Решение 1: memfd_create

Системный вызов позволяет создать «вообще анонимный» файловый дескриптор. Файл находится в памяти и существует, пока на него открыт хоть один дескриптор. В простейшем случае, вы просто получаете такой дескриптор, записываете в него данные через , перематываете , и с помощью даёте о нём знать :

Имя файла, передаваемое первым аргументом, будет отображаться в символьной ссылке в :

Решение 2: open с флагом O_TMPFILE

В Linux, начиная с какой-то версии, при создании файла можно и имя каталога вместо имени файла. В итоге файл, как (приблизительно) говаривал один литературный персонаж, вроде он есть, но его как бы нет… Пишутся ли данные на диск — не знаю, но наверное, это зависит и от файловой системы (кстати, она должна поддерживать этот режим). Файл всё так же исчезает при закрытии последней ссылки, но его можно прикрепить к дереву каталогов с помощью :

Кроме возможности не мучаться с именованием файла, это даёт возможность заполнить файл, настроить права и т. д., а потом атомарно прилинковать в дерево каталогов.

Вызов sleep() в Tkinter и wxPython

Вызовы в Python можно добавить не только для приложений командной строки. При создании графического пользовательского интерфейса (GUI) периодически нужно добавлять отсрочки. К примеру, при создании приложения FTP для скачивания около миллиона файлов будет разумно добавить вызов между партиями, чтобы снизить нагрузку на сервер.

GUI код выполнит всю обработку в основном потоке, называемом циклом обработки событий, или event loop. При использовании внутри кода GUI заблокируется цикл обработки событий.

К счастью, помимо , можно использовать некоторые другие методы специально для этой задачи. Далее мы рассмотрим, как добавить вызовы в Tkinter и wxPython.

Sleep Until a TimePoint

Many times we want the thread to sleep untill a time point in future. That can be acieved using sleep_untill() i.e.

template< class Clock, class Duration >
void sleep_until( const std::chrono::time_point<Clock,Duration>& sleepTime );

Checkout the complete example, here we will put a thread to sleep until a time point in future i.e.

#include <iostream>
#include <thread>
#include <chrono>

// Print Current Time
void print_time_point(std::chrono::system_clock::time_point timePoint)
{
	std::time_t timeStamp = std::chrono::system_clock::to_time_t(timePoint);
	std::cout << std::ctime(&timeStamp) << std::endl;

}

void threadFunc()
{

	std::cout<<"Current Time :: ";
	// Print Current Time
	print_time_point(std::chrono::system_clock::now());

	// create a time point pointing to 10 second in future
	std::chrono::system_clock::time_point timePoint =
			std::chrono::system_clock::now() + std::chrono::seconds(10);

	std::cout << "Going to Sleep Until :: "; print_time_point(timePoint);


	// Sleep Till specified time point
	// Accepts std::chrono::system_clock::time_point as argument
	std::this_thread::sleep_until(timePoint);

	std::cout<<"Current Time :: ";
	// Print Current Time
	print_time_point(std::chrono::system_clock::now());
}

int main()
{
	std::thread th(&threadFunc);
	th.join();
	return 0;
}

Output:

Current Time :: Sat Feb 25 16:44:40 2017
Going to Sleep Until :: Sat Feb 25 16:44:50 2017
Current Time :: Sat Feb 25 16:44:50 2017

SIGTERM vs SIGKILL: Почему вы должны использовать SIGTERM вместо SIGKILL?

Хотя оба эти сигнала используются для уничтожения процесса, между ними есть некоторые различия:

  • SIGTERM грациозно убивает процесс, тогда как SIGKILL немедленно убивает процесс.
  • Сигнал SIGTERM может обрабатываться, игнорироваться и блокироваться, но SIGKILL не может быть обработан или заблокирован.
  • SIGTERM не убивает дочерние процессы. SIGKILL также убивает дочерние процессы.

Некоторые пользователи Linux привыкли использовать kill -9, и этого следует избегать. Если у вас нет процесса без ответа, вам не нужно использовать SIGKILL.

С помощью SIGTERM процесс получает время для отправки информации своим родительским и дочерним процессам. Это дочерние процессы обрабатываются init.

Использование SIGKILL может привести к созданию процесса зомби, потому что уничтоженный процесс не получает возможности сообщить своему родительскому процессу, что он получил сигнал уничтожения.

Мы надеемся, что вы теперь лучше понимаете, как убить процесс с помощью SIGTERM или SIGKILL.

Если у вас есть какие-либо вопросы или предложения, пожалуйста, не стесняйтесь оставлять комментарии.

Использование Queues

Очередь(Queues Python) может быть использована для стековых реализаций «пришел первым – ушел первым» (first-in-first-out (FIFO)) или же «пришел последним – ушел последним» (last-in-last-out (LILO)) , если вы используете их правильно.

В данном разделе, мы смешаем потоки и создадим простой скрипт файлового загрузчика, чтобы продемонстрировать, как работает Queues Python со случаями, которые мы хотим паралеллизировать. Чтобы помочь объяснить, как работает Queues, мы перепишем загрузочный скрипт из предыдущей секции для использования Queues. Приступим!

Python

# -*- coding: utf-8 -*-

import os
import threading
import urllib.request
from queue import Queue

class Downloader(threading.Thread):
«»»Потоковый загрузчик файлов»»»

def __init__(self, queue):
«»»Инициализация потока»»»
threading.Thread.__init__(self)
self.queue = queue

def run(self):
«»»Запуск потока»»»
while True:
# Получаем url из очереди
url = self.queue.get()

# Скачиваем файл
self.download_file(url)

# Отправляем сигнал о том, что задача завершена
self.queue.task_done()

def download_file(self, url):
«»»Скачиваем файл»»»
handle = urllib.request.urlopen(url)
fname = os.path.basename(url)

with open(fname, «wb») as f:
while True:
chunk = handle.read(1024)
if not chunk:
break
f.write(chunk)

def main(urls):
«»»
Запускаем программу
«»»
queue = Queue()

# Запускаем потом и очередь
for i in range(5):
t = Downloader(queue)
t.setDaemon(True)
t.start()

# Даем очереди нужные нам ссылки для скачивания
for url in urls:
queue.put(url)

# Ждем завершения работы очереди
queue.join()

if __name__ == «__main__»:
urls = [«http://www.irs.gov/pub/irs-pdf/f1040.pdf»,
«http://www.irs.gov/pub/irs-pdf/f1040a.pdf»,
«http://www.irs.gov/pub/irs-pdf/f1040ez.pdf»,
«http://www.irs.gov/pub/irs-pdf/f1040es.pdf»,
«http://www.irs.gov/pub/irs-pdf/f1040sb.pdf»]

main(urls)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

# -*- coding: utf-8 -*-
 

importos

importthreading

importurllib.request

fromqueueimportQueue

classDownloader(threading.Thread)

«»»Потоковый загрузчик файлов»»»

def__init__(self,queue)

«»»Инициализация потока»»»

threading.Thread.__init__(self)

self.queue=queue

defrun(self)

«»»Запуск потока»»»

whileTrue

# Получаем url из очереди

url=self.queue.get()

# Скачиваем файл

self.download_file(url)

# Отправляем сигнал о том, что задача завершена

self.queue.task_done()

defdownload_file(self,url)

«»»Скачиваем файл»»»

handle=urllib.request.urlopen(url)

fname=os.path.basename(url)

withopen(fname,»wb»)asf

whileTrue

chunk=handle.read(1024)

ifnotchunk

break

f.write(chunk)

defmain(urls)

«»»

    Запускаем программу
    «»»

queue=Queue()

# Запускаем потом и очередь

foriinrange(5)

t=Downloader(queue)

t.setDaemon(True)

t.start()

# Даем очереди нужные нам ссылки для скачивания

forurl inurls

queue.put(url)

# Ждем завершения работы очереди

queue.join()

if__name__==»__main__»

urls=»http://www.irs.gov/pub/irs-pdf/f1040.pdf»,

«http://www.irs.gov/pub/irs-pdf/f1040a.pdf»,

«http://www.irs.gov/pub/irs-pdf/f1040ez.pdf»,

«http://www.irs.gov/pub/irs-pdf/f1040es.pdf»,

«http://www.irs.gov/pub/irs-pdf/f1040sb.pdf»

main(urls)

Давайте притормозим. В первую очередь, нам нужно взглянуть на определение главной функции для того, чтобы увидеть, как все протекает. Здесь мы видим, что она принимает список url адресов. Далее, функция main создаете экземпляр очереди, которая передана пяти демонизированным потокам. Основная разница между демонизированным и недемонизированным потоком в том, что вам нужно отслеживать недемонизированные потоки и закрывать их вручную, в то время как поток «демон» нужно только запустить и забыть о нем. Когда ваше приложение закроется, закроется и поток. Далее мы загрузили очередь (при помощи метода put) вместе с переданными url. Наконец, мы указываем очереди подождать, пока потоки выполнят свои процессы через метод join. В классе download у нас есть строчка self.queue.get(), которая выполняет функцию блока, пока очередь делает что-либо для возврата. Это значит, что потоки скромно будут дожидаться своей очереди. Также это значит, чтобы поток получал что-нибудь из очереди, он должен вызывать метод очереди под названием get. Таким образом, добавляя что-нибудь в очередь, пул потоков, поднимет или возьмет эти объекты и обработает их. Это также известно как dequeing. После того, как все объекты в очередь обработаны, скрипт заканчивается и закрывается. На моем компьютере были загружены первые 5 документов за секунду.

BUGS top

       If a program that catches signals and uses nanosleep() receives
       signals at a very high rate, then scheduling delays and rounding
       errors in the kernel's calculation of the sleep interval and the
       returned remain value mean that the remain value may steadily
       increase on successive restarts of the nanosleep() call.  To avoid
       such problems, use clock_nanosleep(2) with the TIMER_ABSTIME flag to
       sleep to an absolute deadline.

       In Linux 2.4, if nanosleep() is stopped by a signal (e.g., SIGTSTP),
       then the call fails with the error EINTR after the thread is resumed
       by a SIGCONT signal.  If the system call is subsequently restarted,
       then the time that the thread spent in the stopped state is not
       counted against the sleep interval.  This problem is fixed in Linux
       2.6.0 and later kernels.
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector