Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7864145
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 2, 20262026-06-02T23:41:55+00:00 2026-06-02T23:41:55+00:00

If I want to execute concurrent pysnmp threads with cmdgen.CommandGenerator().nextCmd() , is pysnmp thread-safe?

  • 0

If I want to execute concurrent pysnmp threads with cmdgen.CommandGenerator().nextCmd(), is pysnmp thread-safe?

When I test it, I have not seen issues that would indicate a problem; however, I have not run pysnmp with threading before and the results of these queries will be used to make business decisions, so I would like to get a definitive answer to pysnmp‘s thread-safety.

from threading import Thread
import time

# See SNMP.py module at the bottom of the question
from SNMP import v2c

class SNMP_Walk_Thread(Thread):
    def __init__(self, address='127.0.0.1', oid='sysDescr'):
        Thread.__init__(self)
        self.address = address
        self.oid = oid
        self.results = None

    def run(self):
        self.snmp = v2c(self.address)
        self.results = self.snmp.walk(self.oid)

if __name__=='__main__':
    managers = set()
    finished = set()
    start = time.time()
    for addr in ['172.25.116.20', '172.25.116.21', '172.25.116.22',
        '172.25.116.5']:
        print "Calling %s(address=%s)" % ('SNMP_Walk_Thread', addr)
        poll = SNMP_Walk_Thread(address=addr) 
        poll.start(); managers.add(poll)
    while (len(finished)<len(managers)):
        for instance in managers.difference(finished):
            instance.join(0.5)
            if not instance.is_alive():
                finished.add(instance)
                print "RESULT:", instance.results
    print "   Execution time: %0.3f seconds" % ((time.time()-start))

"""SNMP.py (Updated to include single CommandGenerator() instances per thread, as 
suggested in Ilya's answer"""
from collections import namedtuple as NT
from datetime import datetime
import string
import re

from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp.smi import builder, view, error
from numpy import int64, float64

# NOTE!!!
# It is best to install the pysnmp-mibs package from pypi... this makes
# a lot of symbolic MIB names "just work"


# See this link below for many oneliner examples...
# http://pysnmp.sourceforge.net/examples/4.x/v3arch/oneliner/index.html

class v2c(object):
    """Build an SNMPv2c manager object"""
    def __init__(self, ipaddr=None, device=None, community='Public', 
        retries=3, timeout=9):
        self.device = device
        self.ipaddr = ipaddr
        self.community = community
        self.SNMPObject = NT('SNMPObject', ['modName', 'datetime', 'symName', 
            'index', 'value'])
        self.SNMPIndexed = NT('SNMPIndexed', ['modName', 'datetime', 'symName', 
            'index', 'value'])
        self.query_timeout = float(timeout)/int(retries)
        self.query_retries = int(retries)
        self._index = None

        self.cmdGen = cmdgen.CommandGenerator()
        #mibBuilder = builder.MibBuilder()
        #mibPath = mibBuilder.getMibPath()+('/opt/python/Models/Network/MIBs',)
        #mibBuilder.setMibPath(*mibPath)
        #mibBuilder.loadModules(
        #    'RFC-1213',
        #    )
        #mibView = view.MibViewController(mibBuilder)

    def index(self, oid=None):
        """Build an SNMP Manager index to reference in get or walk operations.  First v2c.index('ifName').  Then, v2c.get_index('ifHCInOctets', 'eth0') or v2c.walk_index('ifHCInOctets').  Instead of referencing a numerical index, the index will refer to the value that was indexed."""
        self._index = dict()
        self._intfobj = dict()
        snmpidx = self.walk(oid=oid)
        for ii in snmpidx:
            ## the dicts below are keyed by the SNMP index number
            # value below is the text string of the intf name
            self._index[ii.index] = ii.value
            # value below is the intf object
            if not (self.device is None):
                self._intfobj[ii.index] = self.device.find_match_intf(ii.value, 
                    enforce_format=False)

    def walk_index(self, oid=None):
        """Example usage, first index with v2c.index('ifName'), then v2c.get_index('ifHCInOctets', 'eth0')"""
        if not (self._index is None):
            tmp = list()
            snmpvals = self.walk(oid=oid)
            for idx, ii in enumerate(snmpvals):
                tmp.append([ii.modName, datetime.now(), ii.symName, 
                    self._index[ii.index], ii.value])

            return map(self.SNMPIndexed._make, tmp)
        else:
            raise ValueError, "Must populate with SNMP.v2c.index() first"

    def walk(self, oid=None):
        if isinstance(self._format(oid), tuple):
            errorIndication, errorStatus, errorIndex, \
            varBindTable = self.cmdGen.nextCmd(  
                        cmdgen.CommunityData('test-agent', self.community),  
                        cmdgen.UdpTransportTarget((self.ipaddr, 161),
                        retries=self.query_retries,
                        timeout=self.query_timeout),  
                        self._format(oid),
                    )
            # Parsing only for now... no return value...
            self._parse(errorIndication, errorStatus, errorIndex, varBindTable)
        elif isinstance(oid, str):
            errorIndication, errorStatus, errorIndex, \
                             varBindTable = self.cmdGen.nextCmd(
                # SNMP v2
                cmdgen.CommunityData('test-agent', self.community),
                # Transport
                cmdgen.UdpTransportTarget((self.ipaddr, 161)),
                (('', oid),),
                )
            return self._parse_resolve(errorIndication, errorStatus, 
                errorIndex, varBindTable)
        else:
            raise ValueError, "Unknown oid format: %s" % oid

    def get_index(self, oid=None, index=None):
        """In this case, index should be similar to the values you indexed from... i.e. if you index with ifName, get_index('ifHCInOctets', 'eth0')"""
        if not (self._index is None) and isinstance(index, str):
            # Map the interface name provided in index to an ifName index...
            snmpvals = None
            for idx, value in self._index.items():
                if index == value:
                    # if there is an exact match between the text index and the
                    # snmp index value...
                    snmpvals = self.get(oid=oid, index=idx)
                    break
            else:
                # TRY mapping the provided text index into an interface obj
                _intfobj = self.device.find_match_intf(index)
                if not (_intfobj is None):
                    for key, val in self._intfobj.items():
                        if (val==_intfobj):
                            snmpvals = self.get(oid=oid, index=key)
                            break

            # Ensure we only parse a valid response...
            if not (snmpvals is None):
                tmp = [snmpvals.modName, datetime.now(), snmpvals.symName, 
                    self._index[snmpvals.index], snmpvals.value]
                return self.SNMPIndexed._make(tmp)

        elif not isinstance(index, str):
            raise ValueError, "index must be a string value"
        else:
            raise ValueError, "Must populate with SNMP.v2c.index() first"

    def get(self, oid=None, index=None):
        if isinstance(self._format(oid), tuple):
            errorIndication, errorStatus, errorIndex, \
            varBindTable = self.cmdGen.getCmd(  
                        cmdgen.CommunityData('test-agent', self.community),  
                        cmdgen.UdpTransportTarget((self.ipaddr, 161),
                        retries=self.query_retries,
                        timeout=self.query_timeout),  
                        self._format(oid),
                    )
            # Parsing only for now... no return value...
            self._parse(errorIndication, errorStatus, errorIndex, varBindTable)
        elif isinstance(oid, str) and isinstance(index, int):
            errorIndication, errorStatus, errorIndex, \
                             varBindTable = self.cmdGen.getCmd(
                # SNMP v2
                cmdgen.CommunityData('test-agent', self.community),
                # Transport
                cmdgen.UdpTransportTarget((self.ipaddr, 161)),
                (('', oid), index),
                )
            return self._parse_resolve(errorIndication, errorStatus, 
                errorIndex, [varBindTable])[0]
        else:
            raise ValueError, "Unknown oid format: %s" % oid

    def bulkwalk(self, oid=None):
        """SNMP bulkwalk a device.  NOTE: This often is faster, but does not work as well as a simple SNMP walk"""
        if isinstance(self._format(oid), tuple):
            errorIndication, errorStatus, errorIndex, varBindTable = self.cmdGen.bulkCmd(  
                        cmdgen.CommunityData('test-agent', self.community),  
                        cmdgen.UdpTransportTarget((self.ipaddr, 161),  
                        retries=self.query_retries,
                        timeout=self.query_timeout), 
                0,
                25,
                self._format(oid),
                )
            return self._parse(errorIndication, errorStatus, 
                errorIndex, varBindTable)
        elif isinstance(oid, str):
            errorIndication, errorStatus, errorIndex, varBindTable = self.cmdGen.bulkCmd(  
                        cmdgen.CommunityData('test-agent', self.community),  
                        cmdgen.UdpTransportTarget((self.ipaddr, 161),  
                        retries=self.query_retries,
                        timeout=self.query_timeout), 
                0,
                25,
                (('', oid),),
                )
            return self._parse_resolve(errorIndication, errorStatus, 
                errorIndex, varBindTable)
        else:
            raise ValueError, "Unknown oid format: %s" % oid

    def _parse_resolve(self, errorIndication=None, errorStatus=None, 
        errorIndex=None, varBindTable=None):
        """Parse MIB walks and resolve into MIB names"""
        retval = list()
        if errorIndication:
            print errorIndication
        else:
            if errorStatus:
                print '%s at %s\n' % (
                    errorStatus.prettyPrint(),
                    varBindTable[-1][int(errorIndex)-1]
                    )
            else:
                for varBindTableRow in varBindTable:
                    for oid, val in varBindTableRow:
                        (symName, modName), indices = cmdgen.mibvar.oidToMibName(
                            self.cmdGen.mibViewController, oid
                            )
                        val = cmdgen.mibvar.cloneFromMibValue(
                            self.cmdGen.mibViewController, modName, symName, 
                            val)
                        # Try to parse the index as an int first, 
                        # then as a string
                        try:
                            index = int(string.join(map(lambda v: v.prettyPrint(), indices), '.'))
                        except ValueError:
                            index = str(string.join(map(lambda v: v.prettyPrint(), indices), '.'))

                        # Re-format values as float or integer, if possible...
                        tmp = val.prettyPrint()
                        if re.search(r"""^\s*\d+\s*$""", tmp):
                            value = int64(tmp)
                        elif re.search(r"""^\s*\d+\.\d+\s*$""", tmp):
                            value = float64(tmp)
                        else:
                            value = tmp

                        retval.append(self.SNMPObject._make([modName, 
                            datetime.now(), symName, index, value]))
            return retval

    def _parse(self, errorIndication, errorStatus, errorIndex, 
        varBindTable):
        if errorIndication:
           print errorIndication
        else:
            if errorStatus:
                print '%s at %s\n' % (
                    errorStatus.prettyPrint(),
                    errorIndex and varBindTable[-1][int(errorIndex)-1] or '?'
                    )
            else:
                for varBindTableRow in varBindTable:
                    for name, val in varBindTableRow:
                        print '%s = %s' % (name.prettyPrint(), val.prettyPrint())

    def _format(self, oid):
        """Format a numerical OID in the form of 1.3.4.1.2.1 into a tuple"""
        if isinstance(oid, str):
            if re.search('(\d+\.)+\d+', oid):
                tmp = list()
                for ii in oid.split('.'):
                    tmp.append(int(ii))
                return tuple(tmp)
        else:
            return oid
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-02T23:41:56+00:00Added an answer on June 2, 2026 at 11:41 pm

    pysnmp should be MT-safe if you run dedicated CommandGenerator instances each in its own thread. Latest pysnmp release (4.2.2) has relevant fixes.

    I’d consider the following changes to your code:

    • use a single and long-living CommandGenerator instance within each thread, that would safe lots of CPU on initialization
    • if all you need is a SNMP v2c, it may be worth a trouble to re-write your app to use lower-level SNMPv1 API – that would almost eliminate all critical sections or bring them under your control, performance would improve as well – low-level GETNEXT implementation
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a fixed thread pool that runs 7 concurrent threads at any time
I have asp.net generated html code. I want execute jQuery click function when user
I want to execute the method uploadingDone() after completion of all three threads. The
I have a situation where I have a callback that I want to execute
I have a .NET 4 WCF service that maintains a thread-safe, in-memory, dictionary cache
I have a embarrassingly parallel problem that I want to execute on multiple processors.
I want to execute a function on all the objects within a List of
I want to execute some Python code, typed at runtime, so I get the
I want to execute a script every 30mins, but i want to use it
I want to execute this script (view source) that uses Google Translate AJAX API

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.