Детали низкого уровня реализации performSelectorOnMainThread:

Я рассматриваю только столбец даты,

Входные данные:

    DATE         Fuel   Price
0   2014-11-06  Diesel  1669
1   2014-11-02  Diesel  1549
2   2014-11-03  Diesel  1529
3   2014-11-06  Diesel  1519
4   2014-11-06  Diesel  1529

df['DATE']= df['DATE'].values.astype(np.int64)
df

Выходные данные:

     DATE                Fuel   Price
0   1415232000000000000 Diesel  1669
1   1414886400000000000 Diesel  1549
2   1414972800000000000 Diesel  1529
3   1415232000000000000 Diesel  1519
4   1415232000000000000 Diesel  1529

Дата была преобразована в timestamp. Чтобы преобразовать его обратно в исходный формат, просто сделайте,

df['DATE'] = pd.to_datetime(df['DATE'], unit='ns')
df

Вывод:

     DATE    Fuel   Price
0   2014-11-06  Diesel  1669
1   2014-11-02  Diesel  1549
2   2014-11-03  Diesel  1529
3   2014-11-06  Diesel  1519
4   2014-11-06  Diesel  1529

Теперь постройте график, используя это,

from matplotlib import pyplot as plt 
%matplotlib inline
plt.title("Analyse")

plt.xlabel("DATE")
plt.ylabel("Price")
plt.scatter(list(df['DATE'].values), list(df['Price'].values))
plt.show()

Вывод: [ 1114]

enter image description here

8
задан rpj 6 March 2009 в 17:35
поделиться

4 ответа

Да, это действительно использует порты Маха. То, что происходит, является этим:

  1. Блок данных, инкапсулирующий выполнить информацию (целевой объект, селектор, аргумент дополнительного объекта селектору, и т.д.), ставится в очередь в информации о цикле выполнения потока. Это сделано с помощью @synchronized, который в конечном счете использует pthread_mutex_lock.
  2. CFRunLoopSourceSignal называют, чтобы сигнализировать, что источник готов стрелять.
  3. CFRunLoopWakeUp называют для уведомления цикла выполнения основного потока, который пора разбудить. Это сделано с помощью mach_msg.

Из документов Apple:

Источниками версии 1 управляют цикл выполнения и ядро. Эти источники используют порты Маха для передачи сигналов, когда источники готовы стрелять. Источник автоматически сообщен ядром, когда сообщение прибывает в порт Маха источника. Содержание сообщения дано источнику для обработки, когда источник запущен. Источники цикла выполнения для CFMachPort и CFMessagePort в настоящее время реализуются как источники версии 1.

Я смотрю на отслеживание стека прямо сейчас, и это - то, что оно показывает:

0 mach_msg
1 CFRunLoopWakeUp
2 -[NSThread _nq:]
3 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:]
4 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:]

Установите точку останова на mach_msg, и Вы сможете подтвердить это.

10
ответ дан 5 December 2019 в 12:14
поделиться

Как сказанный Mecki, более общий механизм, который мог использоваться для реализации -performSelectorOn… NSTimer.

NSTimer бесплатный соединенный мостом к CFRunLoopTimer. Реализация CFRunLoopTimer – хотя не обязательно тот, на самом деле используемый для нормальных процессов в OS X – может быть найден в CFLite (подмножество с открытым исходным кодом CoreFoundation; пакет CF-476.14 в исходном коде Darwin 9.4. (CF-476.15, соответствуя OS X 10.5.5, еще не доступен.)

0
ответ дан 5 December 2019 в 12:14
поделиться

Документация для NSObject's performSelectorOnMainThread:withObject:waitUntilDone: в методе говорится:

Этот метод ставит сообщение в очередь на цикле выполнения основного потока с помощью выполненных режимов цикла по умолчанию — то есть, режимы, связанные с постоянным NSRunLoopCommonModes. Как часть его нормальной обработки цикла выполнения, основной поток исключает сообщение из очереди (предполагающий, что это работает в одном из выполненных режимов цикла по умолчанию), и вызывает требуемый метод.

2
ответ дан 5 December 2019 в 12:14
поделиться

Еще одно редактирование:

Отвечать на вопрос комментария:

какой механизм IPC используется для передачи информации между потоками? Общая память? Сокеты? Мах, обменивающийся сообщениями?

NSThread хранит внутренне ссылку на основной поток, и через ту ссылку можно получить ссылку на NSRunloop того потока. NSRunloop внутренне является связанным списком и путем добавления объекта NSTimer к runloop, новый элемент связанного списка создается и добавляется к списку. Таким образом, Вы могли сказать, что это - общая память, связанный список, который на самом деле принадлежит основному потоку, просто изменяется из другого потока. Существуют взаимные исключения/блокировки (возможно даже объекты NSLock), который удостоверится, редактируя связанный список, ориентировано на многопотоковое исполнение.

Псевдо код:

// Main Thread

for (;;) {
    lock(runloop->runloopLock);
    task = NULL;
    do {
        task = getNextTask(runloop);
        if (!task) {
            // function below unlocks the lock and
            // atomically sends thread to sleep.
            // If thread is woken up again, it will
            // get the lock again before continuing
            // running. See "man pthread_cond_wait"
            // as an example function that works
            // this way
            wait_for_notification(runloop->newTasks, runloop->runloopLock);
        }
    } while (!task);
    unlock(runloop->runloopLock);
    processTask(task);
}


// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object

timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);

Конечно, это упрощено, большинство деталей скрыто между функциями здесь. Например, getNextTask только возвратит таймер, если таймер уже должен был стрелять. Если дата огня каждого таймера находится все еще в будущем и нет никакого другого события для обработки (как клавиатура, событие от нажатия мыши от UI или отправленного уведомления), это возвратило бы ПУСТОЙ УКАЗАТЕЛЬ.


Я все еще не уверен, каков вопрос. Селектор является не чем иным как струной до, содержащей название называемого метода. Каждый метод является нормальной функцией C и там существует таблица строк, содержа имена методов как строки и указатели функции. Это - самые основы, как Objective C на самом деле работает.

Как я записал ниже, объект NSTimer создается, который получает указатель на целевой объект и указатель на струну до, содержащую имя метода и когда таймер стреляет, это находит право C методом для вызова при помощи таблицы строк (следовательно, этому нужно имя строки метода) целевого объекта (следовательно, этому нужна ссылка на него).

Не точно реализация, но достаточно близкий к нему:

Каждый поток в Какао имеет NSRunLoop (это всегда там, Вы никогда не должны создавать на для потока). PerformSelectorOnMainThread создает объект NSTimer как это, тот, который стреляет только однажды и где время для увольнения уже расположено в прошлом (таким образом, ему сразу нужно увольнение), затем получает NSRunLoop основного потока и добавляет объект - таймер там. Как только основной поток идет неактивный, он ищет следующее событие в своем Runloop для обработки (или засыпает, если нет ничего для обработки и разбуженный снова, как только событие добавляется), и выполняет его. Или основной поток занят при планировании вызова, в этом случае он обработает событие таймера, как только он закончил свою текущую задачу, или он спит в данный момент, в этом случае он будет разбужен путем добавления события и сразу обрабатывает его.

Хороший источник, чтобы искать, как Apple, скорее всего, делает его (никто не может сказать наверняка, как после всего его закрытого исходного кода) является GNUStep. Так как GCC может обработать Objective C (это не просто расширение только поставки Apple, даже стандартный GCC может обработать его), однако, имея Obj-C без всех основных классов, которые поставляет Apple, довольно бесполезно, сообщество GNU пыталось повторно реализовать наиболее распространенные классы Obj-C, которые Вы используете на Mac, и их реализацией является OpenSource.

Здесь можно загрузить недавний исходный пакет.

Распакуйте это и взгляните на реализацию NSThread, NSObject и NSTimer для деталей. Я предполагаю, что Apple не делает его очень отличающийся, я мог, вероятно, доказать его с помощью gdb, но почему они сделают это очень отличающийся, чем тот подход? Это - умный подход, который работает очень хорошо :)

2
ответ дан 5 December 2019 в 12:14
поделиться