affinity.get_process_affinity_mask(pid) возвращает ошибку значения 22

#python #multithreading #cpu #affinity

#питон #многопоточность #процессор #аффинити #python #сходство

Вопрос:

Я хочу поместить своих работников потоков на определенный процессор (я хочу проверить, как GIL влияет на мою программу …), и я нахожу стороннюю библиотеку под названием affinity. Я использовал pip install affinity, чтобы сделать его доступным в моей виртуальной машине (Linux), к сожалению, я получил ошибку ниже:

 >>>pid = os.getpid()
>>>affinity.get_process_affinity_mask(pid)
Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: (22, 'Invalid argument')
  

из code insight следует, что он должен работать на платформе Linux:

 ...
elif sys.platform in ('linux2'):
from _affinity import set_process_affinity_mask, get_process_affinity_mask
...
  

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

Ответ №1:

Глядя на код C и справочную страницу для sched_getaffinity, я не слишком удивлен, что это может привести к сбою с «недопустимым аргументом». Код C передается в единственном беззнаковом long, где функция ожидает cpu_set_t, который может содержать до 128 беззнаковых long.

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

Моя система представляет собой двухъядерный процессор с одним процессором, поэтому модуль работает для меня. Настроена ли ваша виртуальная машина с более чем одним физическим процессором? В качестве теста попробуйте перенастроить его, чтобы иметь только один с несколькими ядрами, и посмотрите, добьетесь ли вы большего успеха.

Если я прав, единственный способ обойти это — изменить модуль C для правильной обработки результата cpu_set_t, вероятно, используя макросы, описанные в CPU_SET (3).

Какова среда вашей виртуальной машины? Программное обеспечение виртуальной машины, количество процессоров / ядер, версия Linux? Попробуйте эту тестовую программу и посмотрите, отличается ли ваш результат:

 $ cat test.c 
#include <stdio.h>
// The CPU_SET man page says to use the second definition, but my system
// wouldn't compile this code without the first one.
#define __USE_GNU
#define _GNU_SOURCE
#include <sched.h>
#include <errno.h>

int main(void) {
    cpu_set_t cur_mask;
    unsigned int len = sizeof(cpu_set_t);

    if (sched_getaffinity(0, len, amp;cur_mask) < 0) {
        printf("Error: %dn", errno);
        return errno;
    }

    int cpu_count = CPU_COUNT(amp;cur_mask);
    printf("Cpu count: %d and size needed: %dn", cpu_count, CPU_ALLOC_SIZE(cpu_count));
    return 0;
}
$ gcc -std=c99 test.c 
$ ./a.out 
Cpu count: 2 and size needed: 8
  

В моей системе кажется, что одного неподписанного long достаточно для хранения до 64 процессоров, поэтому это выглядит намного проще, чем я думал. Однако различные аппаратные средства / архитектуры / версии ядра всегда могут отличаться.

Комментарии:

1. Спасибо @ValdarMoridin, к сожалению, у меня все еще та же ошибка, когда я тестировал на виртуальной машине только с 1 процессором (я нашел эту информацию в настройках виртуальной машины, а также с помощью multiprocessing.cpu_count()).